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:
parent
b7a8e43a53
commit
8dd0b9902b
@ -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;
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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_;
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user