When album cover art changes, update songs matching those albums in the playlist

This commit is contained in:
David Sansome 2010-06-18 14:26:46 +00:00
parent b7a8e43a53
commit 8dd0b9902b
6 changed files with 121 additions and 3 deletions

View File

@ -29,6 +29,7 @@ class LibraryPlaylistItem : public PlaylistItem {
void Reload();
Song Metadata() const { return song_; }
void SetMetadata(const Song& song) { song_ = song; }
QUrl Url() const;

View File

@ -72,6 +72,7 @@ Playlist::Playlist(PlaylistBackend* backend, int id, QObject *parent)
Playlist::~Playlist() {
items_.clear();
library_items_by_id_.clear();
}
QVariant Playlist::headerData(int section, Qt::Orientation, int role) const {
@ -603,6 +604,13 @@ QModelIndex Playlist::InsertItemsWithoutUndo(const PlaylistItemList& items,
items_.insert(i, item);
virtual_items_ << virtual_items_.count();
if (item->type() == "Library") {
int id = item->Metadata().id();
if (id != -1) {
library_items_by_id_.insertMulti(id, item);
}
}
if (item == current_item_) {
// It's one we removed before that got re-added through an undo
current_item_index_ = index(i, 0);
@ -820,6 +828,7 @@ void Playlist::Restore() {
items_.clear();
virtual_items_.clear();
library_items_by_id_.clear();
items_ = backend_->GetPlaylistItems(id_);
@ -827,7 +836,14 @@ void Playlist::Restore() {
for (int i=0 ; i<items_.count() ; ++i) {
virtual_items_ << i;
};
if (items_[i]->type() == "Library") {
int id = items_[i]->Metadata().id();
if (id != -1) {
library_items_by_id_.insertMulti(id, items_[i]);
}
}
}
reset();
@ -852,8 +868,17 @@ PlaylistItemList Playlist::RemoveItemsWithoutUndo(int row, int count) {
// Remove items
PlaylistItemList ret;
for (int i=0 ; i<count ; ++i)
ret << items_.takeAt(row);
for (int i=0 ; i<count ; ++i) {
boost::shared_ptr<PlaylistItem> item(items_.takeAt(row));
ret << item;
if (item->type() == "Library") {
int id = item->Metadata().id();
if (id != -1) {
library_items_by_id_.remove(id, item);
}
}
}
endRemoveRows();
@ -1029,3 +1054,7 @@ quint64 Playlist::GetTotalLength() const {
}
return ret;
}
PlaylistItemList Playlist::library_items_by_id(int id) const {
return library_items_by_id_.values(id);
}

View File

@ -112,6 +112,8 @@ class Playlist : public QAbstractListModel {
PlaylistItem::Options current_item_options() const;
Song current_item_metadata() const;
PlaylistItemList library_items_by_id(int id) const;
SongList GetAllSongs() const;
quint64 GetTotalLength() const; // in seconds
@ -200,6 +202,9 @@ class Playlist : public QAbstractListModel {
PlaylistItemList items_;
QList<int> virtual_items_; // Contains the indices into items_ in the order
// that they will be played.
// A map of library ID to playlist item - for fast lookups when library
// items change.
QMultiMap<int, boost::shared_ptr<PlaylistItem> > library_items_by_id_;
QPersistentModelIndex current_item_index_;
QPersistentModelIndex last_played_item_index_;

View File

@ -18,6 +18,8 @@
#include "playlistbackend.h"
#include "playlistmanager.h"
#include "core/utilities.h"
#include "library/librarybackend.h"
#include "library/libraryplaylistitem.h"
#include "playlistparsers/playlistparser.h"
#include <QFileInfo>
@ -47,6 +49,8 @@ void PlaylistManager::Init(LibraryBackend* library_backend,
playlist_backend_ = playlist_backend;
sequence_ = sequence;
connect(library_backend_, SIGNAL(SongsDiscovered(SongList)), SLOT(SongsDiscovered(SongList)));
foreach (const PlaylistBackend::Playlist& p, playlist_backend->GetAllPlaylists()) {
AddPlaylist(p.id, p.name);
}
@ -225,3 +229,17 @@ void PlaylistManager::SelectionChanged(const QItemSelection &selection) {
current_selection_ = selection;
UpdateSummaryText();
}
void PlaylistManager::SongsDiscovered(const SongList& songs) {
// Some songs might've changed in the library, let's update any playlist
// items we have that match those songs
foreach (const Song& song, songs) {
foreach (const Data& data, playlists_) {
PlaylistItemList items = data.p->library_items_by_id(song.id());
foreach (boost::shared_ptr<PlaylistItem> item, items) {
static_cast<LibraryPlaylistItem*>(item.get())->SetMetadata(song);
}
}
}
}

View File

@ -98,6 +98,7 @@ signals:
private slots:
void UpdateSummaryText();
void SongsDiscovered(const SongList& songs);
private:
Playlist* AddPlaylist(int id, const QString& name);

View File

@ -17,6 +17,7 @@
#include "test_utils.h"
#include "gtest/gtest.h"
#include "library/libraryplaylistitem.h"
#include "playlist/playlist.h"
#include "mock_settingsprovider.h"
#include "mock_playlistitem.h"
@ -434,6 +435,69 @@ TEST_F(PlaylistTest, ShuffleThenNext) {
EXPECT_EQ(index-1, playlist_.previous_index());
}
TEST_F(PlaylistTest, LibraryIdMapSingle) {
Song song;
song.Init("title", "artist", "album", 123);
song.set_id(1);
boost::shared_ptr<PlaylistItem> item(new LibraryPlaylistItem(song));
playlist_.InsertItems(PlaylistItemList() << item);
EXPECT_EQ(0, playlist_.library_items_by_id(-1).count());
EXPECT_EQ(0, playlist_.library_items_by_id(0).count());
EXPECT_EQ(0, playlist_.library_items_by_id(2).count());
ASSERT_EQ(1, playlist_.library_items_by_id(1).count());
EXPECT_EQ(song.title(), playlist_.library_items_by_id(1)[0]->Metadata().title());
playlist_.Clear();
EXPECT_EQ(0, playlist_.library_items_by_id(1).count());
}
TEST_F(PlaylistTest, LibraryIdMapInvalid) {
Song invalid;
invalid.Init("title", "artist", "album", 123);
ASSERT_EQ(-1, invalid.id());
boost::shared_ptr<PlaylistItem> item(new LibraryPlaylistItem(invalid));
playlist_.InsertItems(PlaylistItemList() << item);
EXPECT_EQ(0, playlist_.library_items_by_id(-1).count());
EXPECT_EQ(0, playlist_.library_items_by_id(0).count());
EXPECT_EQ(0, playlist_.library_items_by_id(1).count());
EXPECT_EQ(0, playlist_.library_items_by_id(2).count());
}
TEST_F(PlaylistTest, LibraryIdMapMulti) {
Song one;
one.Init("title", "artist", "album", 123);
one.set_id(1);
Song two;
two.Init("title 2", "artist 2", "album 2", 123);
two.set_id(2);
boost::shared_ptr<PlaylistItem> item_one(new LibraryPlaylistItem(one));
boost::shared_ptr<PlaylistItem> item_two(new LibraryPlaylistItem(two));
boost::shared_ptr<PlaylistItem> item_three(new LibraryPlaylistItem(one));
playlist_.InsertItems(PlaylistItemList() << item_one << item_two << item_three);
EXPECT_EQ(2, playlist_.library_items_by_id(1).count());
EXPECT_EQ(1, playlist_.library_items_by_id(2).count());
playlist_.removeRow(1); // item_two
EXPECT_EQ(2, playlist_.library_items_by_id(1).count());
EXPECT_EQ(0, playlist_.library_items_by_id(2).count());
playlist_.removeRow(1); // item_three
EXPECT_EQ(1, playlist_.library_items_by_id(1).count());
EXPECT_EQ(0, playlist_.library_items_by_id(2).count());
playlist_.removeRow(0); // item_one
EXPECT_EQ(0, playlist_.library_items_by_id(1).count());
EXPECT_EQ(0, playlist_.library_items_by_id(2).count());
}
} // namespace