Play last.fm tag radio or similar artists radio when clicking on a tag in the song/artist info pane.
This commit is contained in:
parent
a41b6de040
commit
b97b2138fa
@ -65,7 +65,7 @@ class Player : public QObject {
|
|||||||
Engine::State GetState() const;
|
Engine::State GetState() const;
|
||||||
int GetVolume() const;
|
int GetVolume() const;
|
||||||
|
|
||||||
boost::shared_ptr<PlaylistItem> GetCurrentItem() const { return current_item_; }
|
PlaylistItemPtr GetCurrentItem() const { return current_item_; }
|
||||||
|
|
||||||
// MPRIS
|
// MPRIS
|
||||||
enum DBusCaps {
|
enum DBusCaps {
|
||||||
@ -175,7 +175,7 @@ class Player : public QObject {
|
|||||||
LastFMService* lastfm_;
|
LastFMService* lastfm_;
|
||||||
QSettings settings_;
|
QSettings settings_;
|
||||||
|
|
||||||
boost::shared_ptr<PlaylistItem> current_item_;
|
PlaylistItemPtr current_item_;
|
||||||
|
|
||||||
boost::scoped_ptr<EngineBase> engine_;
|
boost::scoped_ptr<EngineBase> engine_;
|
||||||
Engine::TrackChangeType stream_change_type_;
|
Engine::TrackChangeType stream_change_type_;
|
||||||
|
@ -673,7 +673,7 @@ QModelIndex Playlist::InsertItemsWithoutUndo(const PlaylistItemList& items,
|
|||||||
|
|
||||||
beginInsertRows(QModelIndex(), start, end);
|
beginInsertRows(QModelIndex(), start, end);
|
||||||
for (int i=start ; i<=end ; ++i) {
|
for (int i=start ; i<=end ; ++i) {
|
||||||
boost::shared_ptr<PlaylistItem> item = items[i - start];
|
PlaylistItemPtr item = items[i - start];
|
||||||
items_.insert(i, item);
|
items_.insert(i, item);
|
||||||
virtual_items_ << virtual_items_.count();
|
virtual_items_ << virtual_items_.count();
|
||||||
|
|
||||||
@ -948,7 +948,7 @@ PlaylistItemList Playlist::RemoveItemsWithoutUndo(int row, int count) {
|
|||||||
// Remove items
|
// Remove items
|
||||||
PlaylistItemList ret;
|
PlaylistItemList ret;
|
||||||
for (int i=0 ; i<count ; ++i) {
|
for (int i=0 ; i<count ; ++i) {
|
||||||
boost::shared_ptr<PlaylistItem> item(items_.takeAt(row));
|
PlaylistItemPtr item(items_.takeAt(row));
|
||||||
ret << item;
|
ret << item;
|
||||||
|
|
||||||
if (item->type() == "Library") {
|
if (item->type() == "Library") {
|
||||||
@ -1118,7 +1118,7 @@ QSortFilterProxyModel* Playlist::proxy() const {
|
|||||||
|
|
||||||
SongList Playlist::GetAllSongs() const {
|
SongList Playlist::GetAllSongs() const {
|
||||||
SongList ret;
|
SongList ret;
|
||||||
foreach (boost::shared_ptr<PlaylistItem> item, items_) {
|
foreach (PlaylistItemPtr item, items_) {
|
||||||
ret << item->Metadata();
|
ret << item->Metadata();
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@ -1126,7 +1126,7 @@ SongList Playlist::GetAllSongs() const {
|
|||||||
|
|
||||||
quint64 Playlist::GetTotalLength() const {
|
quint64 Playlist::GetTotalLength() const {
|
||||||
quint64 ret = 0;
|
quint64 ret = 0;
|
||||||
foreach (boost::shared_ptr<PlaylistItem> item, items_) {
|
foreach (PlaylistItemPtr item, items_) {
|
||||||
int length = item->Metadata().length();
|
int length = item->Metadata().length();
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
ret += length;
|
ret += length;
|
||||||
|
@ -94,8 +94,7 @@ class Playlist : public QAbstractListModel {
|
|||||||
static const char* kPlayNowMimetype;
|
static const char* kPlayNowMimetype;
|
||||||
|
|
||||||
static bool CompareItems(int column, Qt::SortOrder order,
|
static bool CompareItems(int column, Qt::SortOrder order,
|
||||||
boost::shared_ptr<PlaylistItem> a,
|
PlaylistItemPtr a, PlaylistItemPtr b);
|
||||||
boost::shared_ptr<PlaylistItem> b);
|
|
||||||
|
|
||||||
static QString column_name(Column column);
|
static QString column_name(Column column);
|
||||||
static bool column_is_editable(Playlist::Column column);
|
static bool column_is_editable(Playlist::Column column);
|
||||||
@ -116,8 +115,8 @@ class Playlist : public QAbstractListModel {
|
|||||||
int previous_index() const;
|
int previous_index() const;
|
||||||
bool stop_after_current() const;
|
bool stop_after_current() const;
|
||||||
|
|
||||||
const boost::shared_ptr<PlaylistItem>& item_at(int index) const { return items_[index]; }
|
const PlaylistItemPtr& item_at(int index) const { return items_[index]; }
|
||||||
boost::shared_ptr<PlaylistItem> current_item() const { return current_item_; }
|
PlaylistItemPtr current_item() const { return current_item_; }
|
||||||
|
|
||||||
PlaylistItem::Options current_item_options() const;
|
PlaylistItem::Options current_item_options() const;
|
||||||
Song current_item_metadata() const;
|
Song current_item_metadata() const;
|
||||||
@ -226,7 +225,7 @@ class Playlist : public QAbstractListModel {
|
|||||||
// that they will be played.
|
// that they will be played.
|
||||||
// A map of library ID to playlist item - for fast lookups when library
|
// A map of library ID to playlist item - for fast lookups when library
|
||||||
// items change.
|
// items change.
|
||||||
QMultiMap<int, boost::shared_ptr<PlaylistItem> > library_items_by_id_;
|
QMultiMap<int, PlaylistItemPtr> library_items_by_id_;
|
||||||
|
|
||||||
QPersistentModelIndex current_item_index_;
|
QPersistentModelIndex current_item_index_;
|
||||||
QPersistentModelIndex last_played_item_index_;
|
QPersistentModelIndex last_played_item_index_;
|
||||||
@ -234,7 +233,7 @@ class Playlist : public QAbstractListModel {
|
|||||||
bool current_is_paused_;
|
bool current_is_paused_;
|
||||||
int current_virtual_index_;
|
int current_virtual_index_;
|
||||||
|
|
||||||
boost::shared_ptr<PlaylistItem> current_item_;
|
PlaylistItemPtr current_item_;
|
||||||
|
|
||||||
bool is_shuffled_;
|
bool is_shuffled_;
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ class PlaylistBackend : public QObject {
|
|||||||
int last_played;
|
int last_played;
|
||||||
};
|
};
|
||||||
typedef QList<Playlist> PlaylistList;
|
typedef QList<Playlist> PlaylistList;
|
||||||
typedef QFuture<boost::shared_ptr<PlaylistItem> > PlaylistItemFuture;
|
typedef QFuture<PlaylistItemPtr> PlaylistItemFuture;
|
||||||
|
|
||||||
PlaylistList GetAllPlaylists();
|
PlaylistList GetAllPlaylists();
|
||||||
Playlist GetPlaylist(int id);
|
Playlist GetPlaylist(int id);
|
||||||
@ -57,7 +57,7 @@ class PlaylistBackend : public QObject {
|
|||||||
void SavePlaylist(int playlist, const PlaylistItemList& items, int last_played);
|
void SavePlaylist(int playlist, const PlaylistItemList& items, int last_played);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static boost::shared_ptr<PlaylistItem> NewSongFromQuery(const SqlRow& row);
|
static PlaylistItemPtr NewSongFromQuery(const SqlRow& row);
|
||||||
|
|
||||||
boost::shared_ptr<Database> db_;
|
boost::shared_ptr<Database> db_;
|
||||||
};
|
};
|
||||||
|
@ -63,7 +63,7 @@ void PlaylistItem::ClearTemporaryMetadata() {
|
|||||||
temp_metadata_ = Song();
|
temp_metadata_ = Song();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReloadPlaylistItem(boost::shared_ptr<PlaylistItem> item) {
|
static void ReloadPlaylistItem(PlaylistItemPtr item) {
|
||||||
item->Reload();
|
item->Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +128,8 @@ class PlaylistItem : public boost::enable_shared_from_this<PlaylistItem> {
|
|||||||
|
|
||||||
Song temp_metadata_;
|
Song temp_metadata_;
|
||||||
};
|
};
|
||||||
typedef QList<boost::shared_ptr<PlaylistItem> > PlaylistItemList;
|
typedef boost::shared_ptr<PlaylistItem> PlaylistItemPtr;
|
||||||
|
typedef QList<PlaylistItemPtr> PlaylistItemList;
|
||||||
|
|
||||||
Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::Options);
|
Q_DECLARE_OPERATORS_FOR_FLAGS(PlaylistItem::Options);
|
||||||
|
|
||||||
|
@ -263,7 +263,7 @@ void PlaylistManager::SongsDiscovered(const SongList& songs) {
|
|||||||
foreach (const Song& song, songs) {
|
foreach (const Song& song, songs) {
|
||||||
foreach (const Data& data, playlists_) {
|
foreach (const Data& data, playlists_) {
|
||||||
PlaylistItemList items = data.p->library_items_by_id(song.id());
|
PlaylistItemList items = data.p->library_items_by_id(song.id());
|
||||||
foreach (boost::shared_ptr<PlaylistItem> item, items) {
|
foreach (PlaylistItemPtr item, items) {
|
||||||
if (item->Metadata().directory_id() != song.directory_id())
|
if (item->Metadata().directory_id() != song.directory_id())
|
||||||
continue;
|
continue;
|
||||||
static_cast<LibraryPlaylistItem*>(item.get())->SetMetadata(song);
|
static_cast<LibraryPlaylistItem*>(item.get())->SetMetadata(song);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "radioitem.h"
|
#include "radioitem.h"
|
||||||
#include "lastfmstationdialog.h"
|
#include "lastfmstationdialog.h"
|
||||||
#include "radiomodel.h"
|
#include "radiomodel.h"
|
||||||
|
#include "radioplaylistitem.h"
|
||||||
#include "core/networkaccessmanager.h"
|
#include "core/networkaccessmanager.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
#include "core/taskmanager.h"
|
#include "core/taskmanager.h"
|
||||||
@ -725,3 +726,25 @@ PlaylistItem::Options LastFMService::playlistitem_options() const {
|
|||||||
PlaylistItem::PauseDisabled |
|
PlaylistItem::PauseDisabled |
|
||||||
PlaylistItem::ContainsMultipleTracks;
|
PlaylistItem::ContainsMultipleTracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
QStringList sections(url.path().split("/", QString::SkipEmptyParts));
|
||||||
|
|
||||||
|
if (sections.count() == 2 && url.host() == "artist" && sections[1] == "similarartists") {
|
||||||
|
ret.reset(new RadioPlaylistItem(this, url,
|
||||||
|
tr("Last.fm Similar Artists to %1").arg(sections[0]), QString()));
|
||||||
|
} else if (sections.count() == 1 && url.host() == "globaltags") {
|
||||||
|
ret.reset(new RadioPlaylistItem(this, url,
|
||||||
|
tr("Last.fm Tag Radio: %1").arg(sections[0]), QString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -32,6 +32,7 @@ uint qHash(const lastfm::Track& track);
|
|||||||
#include "radioservice.h"
|
#include "radioservice.h"
|
||||||
#include "lastfmstationdialog.h"
|
#include "lastfmstationdialog.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
#include "playlist/playlistitem.h"
|
||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
@ -104,11 +105,14 @@ class LastFMService : public RadioService {
|
|||||||
|
|
||||||
void FetchMoreTracks();
|
void FetchMoreTracks();
|
||||||
|
|
||||||
|
PlaylistItemPtr PlaylistItemForUrl(const QUrl& url);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void NowPlaying(const Song& song);
|
void NowPlaying(const Song& song);
|
||||||
void Scrobble();
|
void Scrobble();
|
||||||
void Love();
|
void Love();
|
||||||
void Ban();
|
void Ban();
|
||||||
|
void ShowConfig();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void AuthenticationComplete(bool success);
|
void AuthenticationComplete(bool success);
|
||||||
@ -119,7 +123,6 @@ class LastFMService : public RadioService {
|
|||||||
void AuthenticateReplyFinished();
|
void AuthenticateReplyFinished();
|
||||||
void RefreshFriendsFinished();
|
void RefreshFriendsFinished();
|
||||||
void RefreshNeighboursFinished();
|
void RefreshNeighboursFinished();
|
||||||
void ShowConfig();
|
|
||||||
|
|
||||||
void TunerTrackAvailable();
|
void TunerTrackAvailable();
|
||||||
void TunerError(lastfm::ws::Error error);
|
void TunerError(lastfm::ws::Error error);
|
||||||
|
@ -212,4 +212,8 @@ void SongInfoBase::ConnectWidget(QWidget* widget) {
|
|||||||
if (widget->metaObject()->indexOfSignal("ShowSettingsDialog()") != -1) {
|
if (widget->metaObject()->indexOfSignal("ShowSettingsDialog()") != -1) {
|
||||||
connect(widget, SIGNAL(ShowSettingsDialog()), SIGNAL(ShowSettingsDialog()));
|
connect(widget, SIGNAL(ShowSettingsDialog()), SIGNAL(ShowSettingsDialog()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (widget->metaObject()->indexOfSignal("AddPlaylistItems(PlaylistItemList)") != -1) {
|
||||||
|
connect(widget, SIGNAL(AddPlaylistItems(PlaylistItemList)), SIGNAL(AddPlaylistItems(PlaylistItemList)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "collapsibleinfopane.h"
|
#include "collapsibleinfopane.h"
|
||||||
#include "songinfofetcher.h"
|
#include "songinfofetcher.h"
|
||||||
#include "core/song.h"
|
#include "core/song.h"
|
||||||
|
#include "playlist/playlistitem.h"
|
||||||
#include "widgets/widgetfadehelper.h"
|
#include "widgets/widgetfadehelper.h"
|
||||||
|
|
||||||
class CollapsibleInfoPane;
|
class CollapsibleInfoPane;
|
||||||
@ -46,6 +47,7 @@ public slots:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void ShowSettingsDialog();
|
void ShowSettingsDialog();
|
||||||
|
void AddPlaylistItems(const PlaylistItemList& items);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void showEvent(QShowEvent* e);
|
void showEvent(QShowEvent* e);
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tagwidget.h"
|
#include "tagwidget.h"
|
||||||
|
#include "radio/lastfmservice.h"
|
||||||
|
#include "radio/radiomodel.h"
|
||||||
#include "ui/flowlayout.h"
|
#include "ui/flowlayout.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
@ -93,6 +95,10 @@ void TagWidgetTag::paintEvent(QPaintEvent*) {
|
|||||||
p.drawText(text_rect, text_);
|
p.drawText(text_rect, text_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TagWidgetTag::mouseReleaseEvent(QMouseEvent*) {
|
||||||
|
emit Clicked();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TagWidget::TagWidget(QWidget* parent)
|
TagWidget::TagWidget(QWidget* parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
@ -105,6 +111,27 @@ void TagWidget::AddTag(const QString& tag) {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
TagWidgetTag* widget = new TagWidgetTag(icon_, tag, this);
|
TagWidgetTag* widget = new TagWidgetTag(icon_, tag, this);
|
||||||
|
connect(widget, SIGNAL(Clicked()), SLOT(TagClicked()));
|
||||||
|
|
||||||
layout()->addWidget(widget);
|
layout()->addWidget(widget);
|
||||||
tags_ << widget;
|
tags_ << widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TagWidget::TagClicked() {
|
||||||
|
TagWidgetTag* tag = qobject_cast<TagWidgetTag*>(sender());
|
||||||
|
if (!tag)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LastFMService* last_fm = RadioModel::Service<LastFMService>();
|
||||||
|
if (!last_fm->IsAuthenticated()) {
|
||||||
|
last_fm->ShowConfig();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl url(url_pattern_.arg(tag->text()));
|
||||||
|
PlaylistItemPtr item(last_fm->PlaylistItemForUrl(url));
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
emit AddPlaylistItems(PlaylistItemList() << item);
|
||||||
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
#ifndef TAGWIDGET_H
|
#ifndef TAGWIDGET_H
|
||||||
#define TAGWIDGET_H
|
#define TAGWIDGET_H
|
||||||
|
|
||||||
|
#include "playlist/playlistitem.h"
|
||||||
|
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
@ -40,11 +42,16 @@ public:
|
|||||||
void set_background_opacity(float opacity);
|
void set_background_opacity(float opacity);
|
||||||
|
|
||||||
QSize sizeHint() const;
|
QSize sizeHint() const;
|
||||||
|
QString text() const { return text_; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void Clicked();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void enterEvent(QEvent*);
|
void enterEvent(QEvent*);
|
||||||
void leaveEvent(QEvent*);
|
void leaveEvent(QEvent*);
|
||||||
void paintEvent(QPaintEvent*);
|
void paintEvent(QPaintEvent*);
|
||||||
|
void mouseReleaseEvent(QMouseEvent*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString text_;
|
QString text_;
|
||||||
@ -66,6 +73,12 @@ public:
|
|||||||
|
|
||||||
int count() const { return tags_.count(); }
|
int count() const { return tags_.count(); }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void AddPlaylistItems(const PlaylistItemList& items);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void TagClicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString url_pattern_;
|
QString url_pattern_;
|
||||||
QIcon icon_;
|
QIcon icon_;
|
||||||
|
@ -1596,6 +1596,7 @@ void MainWindow::ConnectInfoView(SongInfoBase* view) {
|
|||||||
connect(player_, SIGNAL(Stopped()), view, SLOT(SongFinished()));
|
connect(player_, SIGNAL(Stopped()), view, SLOT(SongFinished()));
|
||||||
|
|
||||||
connect(view, SIGNAL(ShowSettingsDialog()), SLOT(ShowSongInfoConfig()));
|
connect(view, SIGNAL(ShowSettingsDialog()), SLOT(ShowSongInfoConfig()));
|
||||||
|
connect(view, SIGNAL(AddPlaylistItems(PlaylistItemList)), SLOT(InsertRadioItems(PlaylistItemList)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ShowSongInfoConfig() {
|
void MainWindow::ShowSongInfoConfig() {
|
||||||
|
@ -440,7 +440,7 @@ TEST_F(PlaylistTest, LibraryIdMapSingle) {
|
|||||||
song.Init("title", "artist", "album", 123);
|
song.Init("title", "artist", "album", 123);
|
||||||
song.set_id(1);
|
song.set_id(1);
|
||||||
|
|
||||||
boost::shared_ptr<PlaylistItem> item(new LibraryPlaylistItem(song));
|
PlaylistItemPtr item(new LibraryPlaylistItem(song));
|
||||||
playlist_.InsertItems(PlaylistItemList() << item);
|
playlist_.InsertItems(PlaylistItemList() << item);
|
||||||
|
|
||||||
EXPECT_EQ(0, playlist_.library_items_by_id(-1).count());
|
EXPECT_EQ(0, playlist_.library_items_by_id(-1).count());
|
||||||
@ -459,7 +459,7 @@ TEST_F(PlaylistTest, LibraryIdMapInvalid) {
|
|||||||
invalid.Init("title", "artist", "album", 123);
|
invalid.Init("title", "artist", "album", 123);
|
||||||
ASSERT_EQ(-1, invalid.id());
|
ASSERT_EQ(-1, invalid.id());
|
||||||
|
|
||||||
boost::shared_ptr<PlaylistItem> item(new LibraryPlaylistItem(invalid));
|
PlaylistItemPtr item(new LibraryPlaylistItem(invalid));
|
||||||
playlist_.InsertItems(PlaylistItemList() << item);
|
playlist_.InsertItems(PlaylistItemList() << item);
|
||||||
|
|
||||||
EXPECT_EQ(0, playlist_.library_items_by_id(-1).count());
|
EXPECT_EQ(0, playlist_.library_items_by_id(-1).count());
|
||||||
@ -477,9 +477,9 @@ TEST_F(PlaylistTest, LibraryIdMapMulti) {
|
|||||||
two.Init("title 2", "artist 2", "album 2", 123);
|
two.Init("title 2", "artist 2", "album 2", 123);
|
||||||
two.set_id(2);
|
two.set_id(2);
|
||||||
|
|
||||||
boost::shared_ptr<PlaylistItem> item_one(new LibraryPlaylistItem(one));
|
PlaylistItemPtr item_one(new LibraryPlaylistItem(one));
|
||||||
boost::shared_ptr<PlaylistItem> item_two(new LibraryPlaylistItem(two));
|
PlaylistItemPtr item_two(new LibraryPlaylistItem(two));
|
||||||
boost::shared_ptr<PlaylistItem> item_three(new LibraryPlaylistItem(one));
|
PlaylistItemPtr item_three(new LibraryPlaylistItem(one));
|
||||||
playlist_.InsertItems(PlaylistItemList() << item_one << item_two << item_three);
|
playlist_.InsertItems(PlaylistItemList() << item_one << item_two << item_three);
|
||||||
|
|
||||||
EXPECT_EQ(2, playlist_.library_items_by_id(1).count());
|
EXPECT_EQ(2, playlist_.library_items_by_id(1).count());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user