1
0
mirror of https://github.com/clementine-player/Clementine synced 2025-01-31 11:35:24 +01:00

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(); void Reload();
Song Metadata() const { return song_; } Song Metadata() const { return song_; }
void SetMetadata(const Song& song) { song_ = song; }
QUrl Url() const; QUrl Url() const;

View File

@ -72,6 +72,7 @@ Playlist::Playlist(PlaylistBackend* backend, int id, QObject *parent)
Playlist::~Playlist() { Playlist::~Playlist() {
items_.clear(); items_.clear();
library_items_by_id_.clear();
} }
QVariant Playlist::headerData(int section, Qt::Orientation, int role) const { QVariant Playlist::headerData(int section, Qt::Orientation, int role) const {
@ -603,6 +604,13 @@ QModelIndex Playlist::InsertItemsWithoutUndo(const PlaylistItemList& items,
items_.insert(i, item); items_.insert(i, item);
virtual_items_ << virtual_items_.count(); 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_) { if (item == current_item_) {
// It's one we removed before that got re-added through an undo // It's one we removed before that got re-added through an undo
current_item_index_ = index(i, 0); current_item_index_ = index(i, 0);
@ -820,6 +828,7 @@ void Playlist::Restore() {
items_.clear(); items_.clear();
virtual_items_.clear(); virtual_items_.clear();
library_items_by_id_.clear();
items_ = backend_->GetPlaylistItems(id_); items_ = backend_->GetPlaylistItems(id_);
@ -827,7 +836,14 @@ void Playlist::Restore() {
for (int i=0 ; i<items_.count() ; ++i) { for (int i=0 ; i<items_.count() ; ++i) {
virtual_items_ << 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(); reset();
@ -852,8 +868,17 @@ 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) {
ret << items_.takeAt(row); 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(); endRemoveRows();
@ -1029,3 +1054,7 @@ quint64 Playlist::GetTotalLength() const {
} }
return ret; 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; PlaylistItem::Options current_item_options() const;
Song current_item_metadata() const; Song current_item_metadata() const;
PlaylistItemList library_items_by_id(int id) const;
SongList GetAllSongs() const; SongList GetAllSongs() const;
quint64 GetTotalLength() const; // in seconds quint64 GetTotalLength() const; // in seconds
@ -200,6 +202,9 @@ class Playlist : public QAbstractListModel {
PlaylistItemList items_; PlaylistItemList items_;
QList<int> virtual_items_; // Contains the indices into items_ in the order QList<int> virtual_items_; // Contains the indices into items_ in the order
// that they will be played. // 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 current_item_index_;
QPersistentModelIndex last_played_item_index_; QPersistentModelIndex last_played_item_index_;

View File

@ -18,6 +18,8 @@
#include "playlistbackend.h" #include "playlistbackend.h"
#include "playlistmanager.h" #include "playlistmanager.h"
#include "core/utilities.h" #include "core/utilities.h"
#include "library/librarybackend.h"
#include "library/libraryplaylistitem.h"
#include "playlistparsers/playlistparser.h" #include "playlistparsers/playlistparser.h"
#include <QFileInfo> #include <QFileInfo>
@ -47,6 +49,8 @@ void PlaylistManager::Init(LibraryBackend* library_backend,
playlist_backend_ = playlist_backend; playlist_backend_ = playlist_backend;
sequence_ = sequence; sequence_ = sequence;
connect(library_backend_, SIGNAL(SongsDiscovered(SongList)), SLOT(SongsDiscovered(SongList)));
foreach (const PlaylistBackend::Playlist& p, playlist_backend->GetAllPlaylists()) { foreach (const PlaylistBackend::Playlist& p, playlist_backend->GetAllPlaylists()) {
AddPlaylist(p.id, p.name); AddPlaylist(p.id, p.name);
} }
@ -225,3 +229,17 @@ void PlaylistManager::SelectionChanged(const QItemSelection &selection) {
current_selection_ = selection; current_selection_ = selection;
UpdateSummaryText(); 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: private slots:
void UpdateSummaryText(); void UpdateSummaryText();
void SongsDiscovered(const SongList& songs);
private: private:
Playlist* AddPlaylist(int id, const QString& name); Playlist* AddPlaylist(int id, const QString& name);

View File

@ -17,6 +17,7 @@
#include "test_utils.h" #include "test_utils.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "library/libraryplaylistitem.h"
#include "playlist/playlist.h" #include "playlist/playlist.h"
#include "mock_settingsprovider.h" #include "mock_settingsprovider.h"
#include "mock_playlistitem.h" #include "mock_playlistitem.h"
@ -434,6 +435,69 @@ TEST_F(PlaylistTest, ShuffleThenNext) {
EXPECT_EQ(index-1, playlist_.previous_index()); 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 } // namespace