Do most item reloading in the background, schedule playlist saving
This commit is contained in:
parent
41b238e87b
commit
8c64d3b55c
@ -2013,13 +2013,14 @@ void MainWindow::RescanSongs() {
|
||||
songs << item->Metadata();
|
||||
}
|
||||
else if (item->Metadata().source() == Song::Source_LocalFile) {
|
||||
item->Reload();
|
||||
QPersistentModelIndex persistent_index = QPersistentModelIndex(source_index);
|
||||
app_->playlist_manager()->current()->ItemReload(persistent_index, item->OriginalMetadata(), false);
|
||||
}
|
||||
}
|
||||
|
||||
if (songs.isEmpty()) return;
|
||||
|
||||
app_->collection()->Rescan(songs);
|
||||
if (!songs.isEmpty()) {
|
||||
app_->collection()->Rescan(songs);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2057,7 +2058,7 @@ void MainWindow::EditTagDialogAccepted() {
|
||||
// FIXME: This is really lame but we don't know what rows have changed.
|
||||
ui_->playlist->view()->update();
|
||||
|
||||
app_->playlist_manager()->current()->Save();
|
||||
app_->playlist_manager()->current()->ScheduleSave();
|
||||
|
||||
}
|
||||
|
||||
@ -2259,8 +2260,12 @@ void MainWindow::PlaylistClearCurrent() {
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::PlaylistEditFinished(const QModelIndex &idx) {
|
||||
if (idx == playlist_menu_index_) SelectionSetValue();
|
||||
void MainWindow::PlaylistEditFinished(const int playlist_id, const QModelIndex &idx) {
|
||||
|
||||
if (app_->playlist_manager()->current() && playlist_id == app_->playlist_manager()->current()->id() && idx == playlist_menu_index_) {
|
||||
SelectionSetValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::CommandlineOptionsReceived(const quint32 instanceId, const QByteArray &string_options) {
|
||||
|
@ -158,7 +158,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
||||
void PlaylistQueuePlayNext();
|
||||
void PlaylistSkip();
|
||||
void PlaylistRemoveCurrent();
|
||||
void PlaylistEditFinished(const QModelIndex &idx);
|
||||
void PlaylistEditFinished(const int playlist_id, const QModelIndex &idx);
|
||||
void PlaylistClearCurrent();
|
||||
void RescanSongs();
|
||||
void EditTracks();
|
||||
|
@ -58,6 +58,7 @@
|
||||
#include <QFlags>
|
||||
#include <QSettings>
|
||||
#include <QtDebug>
|
||||
#include <QTimer>
|
||||
|
||||
#include "core/application.h"
|
||||
#include "core/logging.h"
|
||||
@ -116,6 +117,7 @@ Playlist::Playlist(PlaylistBackend *backend, TaskManager *task_manager, Collecti
|
||||
is_loading_(false),
|
||||
proxy_(new PlaylistFilter(this)),
|
||||
queue_(new Queue(this)),
|
||||
timer_save_(new QTimer(this)),
|
||||
backend_(backend),
|
||||
task_manager_(task_manager),
|
||||
collection_(collection),
|
||||
@ -154,8 +156,13 @@ Playlist::Playlist(PlaylistBackend *backend, TaskManager *task_manager, Collecti
|
||||
|
||||
QObject::connect(queue_, &Queue::layoutChanged, this, &Playlist::QueueLayoutChanged);
|
||||
|
||||
QObject::connect(timer_save_, &QTimer::timeout, this, &Playlist::Save);
|
||||
|
||||
column_alignments_ = PlaylistView::DefaultColumnAlignment();
|
||||
|
||||
timer_save_->setSingleShot(true);
|
||||
timer_save_->setInterval(900);
|
||||
|
||||
}
|
||||
|
||||
Playlist::~Playlist() {
|
||||
@ -391,31 +398,22 @@ bool Playlist::setData(const QModelIndex &idx, const QVariant &value, int role)
|
||||
if (song.url().isLocalFile()) {
|
||||
TagReaderReply *reply = TagReaderClient::Instance()->SaveFile(song.url().toLocalFile(), song);
|
||||
QPersistentModelIndex persistent_index = QPersistentModelIndex(idx);
|
||||
QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index]() { SongSaveComplete(reply, persistent_index); }, Qt::QueuedConnection);
|
||||
QObject::connect(reply, &TagReaderReply::Finished, this, [this, reply, persistent_index, item]() { SongSaveComplete(reply, persistent_index, item->OriginalMetadata()); }, Qt::QueuedConnection);
|
||||
}
|
||||
else if (song.source() == Song::Source_Stream) {
|
||||
item->SetMetadata(song);
|
||||
Save();
|
||||
ScheduleSave();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void Playlist::SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx) {
|
||||
void Playlist::SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx, const Song &old_metadata) {
|
||||
|
||||
if (reply->is_successful() && idx.isValid()) {
|
||||
if (reply->message().save_file_response().success()) {
|
||||
PlaylistItemPtr item = item_at(idx.row());
|
||||
if (item) {
|
||||
QFuture<void> future = item->BackgroundReload();
|
||||
QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<void>::finished, this, [this, watcher, idx]() {
|
||||
ItemReloadComplete(idx);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
ItemReload(idx, old_metadata, true);
|
||||
}
|
||||
else {
|
||||
emit Error(tr("An error occurred writing metadata to '%1'").arg(QString::fromStdString(reply->request_message().save_file_request().filename())));
|
||||
@ -426,17 +424,43 @@ void Playlist::SongSaveComplete(TagReaderReply *reply, const QPersistentModelInd
|
||||
|
||||
}
|
||||
|
||||
void Playlist::ItemReloadComplete(const QPersistentModelIndex &idx) {
|
||||
void Playlist::ItemReload(const QPersistentModelIndex &idx, const Song &old_metadata, const bool metadata_edit) {
|
||||
|
||||
if (idx.isValid()) {
|
||||
|
||||
PlaylistItemPtr item = item_at(idx.row());
|
||||
if (item && item->HasTemporaryMetadata()) { // Update temporary metadata.
|
||||
item->UpdateTemporaryMetadata(item->OriginalMetadata());
|
||||
if (item) {
|
||||
QFuture<void> future = item->BackgroundReload();
|
||||
QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
|
||||
watcher->setFuture(future);
|
||||
QObject::connect(watcher, &QFutureWatcher<void>::finished, this, [this, watcher, idx, old_metadata, metadata_edit]() {
|
||||
ItemReloadComplete(idx, old_metadata, metadata_edit);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
emit dataChanged(idx, idx);
|
||||
emit EditingFinished(idx);
|
||||
}
|
||||
|
||||
void Playlist::ItemReloadComplete(const QPersistentModelIndex &idx, const Song &old_metadata, const bool metadata_edit) {
|
||||
|
||||
if (idx.isValid()) {
|
||||
PlaylistItemPtr item = item_at(idx.row());
|
||||
if (item) {
|
||||
if (idx.row() == current_row()) {
|
||||
const bool minor = old_metadata.title() == item->Metadata().title() &&
|
||||
old_metadata.albumartist() == item->Metadata().albumartist() &&
|
||||
old_metadata.artist() == item->Metadata().artist() &&
|
||||
old_metadata.album() == item->Metadata().album();
|
||||
InformOfCurrentSongChange(AutoScroll_Never, minor);
|
||||
}
|
||||
else {
|
||||
emit dataChanged(index(idx.row(), 0), index(idx.row(), ColumnCount - 1));
|
||||
}
|
||||
if (metadata_edit) {
|
||||
emit EditingFinished(id_, idx);
|
||||
}
|
||||
ScheduleSave();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -691,7 +715,7 @@ void Playlist::set_current_row(const int i, const AutoScroll autoscroll, const b
|
||||
|
||||
if (current_item_index_.isValid()) {
|
||||
last_played_item_index_ = current_item_index_;
|
||||
Save();
|
||||
ScheduleSave();
|
||||
}
|
||||
|
||||
UpdateScrobblePoint();
|
||||
@ -859,7 +883,8 @@ void Playlist::TurnOnDynamicPlaylist(PlaylistGeneratorPtr gen) {
|
||||
dynamic_playlist_ = gen;
|
||||
ShuffleModeChanged(PlaylistSequence::Shuffle_Off);
|
||||
emit DynamicModeChanged(true);
|
||||
Save();
|
||||
|
||||
ScheduleSave();
|
||||
|
||||
}
|
||||
|
||||
@ -913,7 +938,8 @@ void Playlist::MoveItemsWithoutUndo(const QList<int> &source_rows, int pos) {
|
||||
current_virtual_index_ = virtual_items_.indexOf(current_row());
|
||||
|
||||
emit layoutChanged();
|
||||
Save();
|
||||
|
||||
ScheduleSave();
|
||||
|
||||
}
|
||||
|
||||
@ -963,7 +989,8 @@ void Playlist::MoveItemsWithoutUndo(int start, const QList<int> &dest_rows) {
|
||||
current_virtual_index_ = virtual_items_.indexOf(current_row());
|
||||
|
||||
emit layoutChanged();
|
||||
Save();
|
||||
|
||||
ScheduleSave();
|
||||
|
||||
}
|
||||
|
||||
@ -1071,7 +1098,7 @@ void Playlist::InsertItemsWithoutUndo(const PlaylistItemList &items, const int p
|
||||
queue_->InsertFirst(indexes);
|
||||
}
|
||||
|
||||
Save();
|
||||
ScheduleSave();
|
||||
|
||||
if (auto_sort_) {
|
||||
sort(sort_column_, sort_order_);
|
||||
@ -1158,7 +1185,8 @@ void Playlist::UpdateItems(SongList songs) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Save();
|
||||
|
||||
ScheduleSave();
|
||||
|
||||
}
|
||||
|
||||
@ -1378,7 +1406,8 @@ void Playlist::ReOrderWithoutUndo(const PlaylistItemList &new_items) {
|
||||
emit layoutChanged();
|
||||
|
||||
emit PlaylistChanged();
|
||||
Save();
|
||||
|
||||
ScheduleSave();
|
||||
|
||||
}
|
||||
|
||||
@ -1394,8 +1423,18 @@ void Playlist::SetCurrentIsPaused(const bool paused) {
|
||||
|
||||
current_is_paused_ = paused;
|
||||
|
||||
if (current_item_index_.isValid())
|
||||
if (current_item_index_.isValid()) {
|
||||
emit dataChanged(index(current_item_index_.row(), 0), index(current_item_index_.row(), ColumnCount - 1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Playlist::ScheduleSave() const {
|
||||
|
||||
if (!backend_ || is_loading_) return;
|
||||
|
||||
timer_save_->start();
|
||||
|
||||
}
|
||||
|
||||
void Playlist::Save() const {
|
||||
@ -1604,7 +1643,8 @@ PlaylistItemList Playlist::RemoveItemsWithoutUndo(const int row, const int count
|
||||
else
|
||||
current_virtual_index_ = virtual_items_.indexOf(current_row());
|
||||
|
||||
Save();
|
||||
ScheduleSave();
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
@ -1695,7 +1735,7 @@ void Playlist::Clear() {
|
||||
|
||||
TurnOffDynamicPlaylist();
|
||||
|
||||
Save();
|
||||
ScheduleSave();
|
||||
|
||||
}
|
||||
|
||||
@ -1750,24 +1790,23 @@ void Playlist::ReloadItems(const QList<int> &rows) {
|
||||
|
||||
for (int row : rows) {
|
||||
PlaylistItemPtr item = item_at(row);
|
||||
|
||||
Song old_metadata = item->Metadata();
|
||||
|
||||
item->Reload();
|
||||
|
||||
if (row == current_row()) {
|
||||
const bool minor = old_metadata.title() == item->Metadata().title() &&
|
||||
old_metadata.albumartist() == item->Metadata().albumartist() &&
|
||||
old_metadata.artist() == item->Metadata().artist() &&
|
||||
old_metadata.album() == item->Metadata().album();
|
||||
InformOfCurrentSongChange(AutoScroll_Never, minor);
|
||||
}
|
||||
else {
|
||||
emit dataChanged(index(row, 0), index(row, ColumnCount - 1));
|
||||
QPersistentModelIndex idx = index(row, 0);
|
||||
if (idx.isValid()) {
|
||||
ItemReload(idx, item->Metadata(), false);
|
||||
}
|
||||
}
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
void Playlist::ReloadItemsBlocking(const QList<int> &rows) {
|
||||
|
||||
for (int row : rows) {
|
||||
PlaylistItemPtr item = item_at(row);
|
||||
Song old_metadata = item->Metadata();
|
||||
item->Reload();
|
||||
QPersistentModelIndex idx = index(row, 0);
|
||||
ItemReloadComplete(idx, old_metadata, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1990,7 +2029,7 @@ void Playlist::ItemChanged(PlaylistItemPtr item) {
|
||||
|
||||
void Playlist::InformOfCurrentSongChange(const AutoScroll autoscroll, const bool minor) {
|
||||
|
||||
// if the song is invalid, we won't play it - there's no point in informing anybody about the change
|
||||
// If the song is invalid, we won't play it - there's no point in informing anybody about the change
|
||||
const Song metadata(current_item_metadata());
|
||||
if (metadata.is_valid()) {
|
||||
if (minor) {
|
||||
@ -2031,8 +2070,14 @@ void Playlist::InvalidateDeletedSongs() {
|
||||
}
|
||||
}
|
||||
|
||||
if (!invalidated_rows.isEmpty())
|
||||
ReloadItems(invalidated_rows);
|
||||
if (!invalidated_rows.isEmpty()) {
|
||||
if (QThread::currentThread() == thread()) {
|
||||
ReloadItems(invalidated_rows);
|
||||
}
|
||||
else {
|
||||
ReloadItemsBlocking(invalidated_rows);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -2195,7 +2240,7 @@ void Playlist::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &
|
||||
if (item && item->Metadata() == song && (!item->Metadata().art_manual_is_valid() || (result.type == AlbumCoverLoaderResult::Type_ManuallyUnset && !item->Metadata().has_manually_unset_cover()))) {
|
||||
qLog(Debug) << "Updating art manual for local song" << song.title() << song.album() << song.title() << "to" << result.album_cover.cover_url << "in playlist.";
|
||||
item->SetArtManual(result.album_cover.cover_url);
|
||||
Save();
|
||||
ScheduleSave();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2214,7 +2259,8 @@ void Playlist::TurnOffDynamicPlaylist() {
|
||||
}
|
||||
|
||||
emit DynamicModeChanged(false);
|
||||
Save();
|
||||
|
||||
ScheduleSave();
|
||||
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@
|
||||
class QMimeData;
|
||||
class QSortFilterProxyModel;
|
||||
class QUndoStack;
|
||||
class QTimer;
|
||||
|
||||
class CollectionBackend;
|
||||
class PlaylistBackend;
|
||||
@ -184,7 +185,7 @@ class Playlist : public QAbstractListModel {
|
||||
static bool set_column_value(Song &song, Column column, const QVariant &value);
|
||||
|
||||
// Persistence
|
||||
void Save() const;
|
||||
void ScheduleSave() const;
|
||||
void Restore();
|
||||
|
||||
// Accessors
|
||||
@ -260,6 +261,7 @@ class Playlist : public QAbstractListModel {
|
||||
|
||||
void StopAfter(const int row);
|
||||
void ReloadItems(const QList<int> &rows);
|
||||
void ReloadItemsBlocking(const QList<int> &rows);
|
||||
void InformOfCurrentSongChange(const AutoScroll autoscroll, const bool minor);
|
||||
|
||||
// Registers an object which will get notifications when new songs are about to be inserted into this playlist.
|
||||
@ -297,6 +299,8 @@ class Playlist : public QAbstractListModel {
|
||||
|
||||
void set_auto_sort(const bool auto_sort) { auto_sort_ = auto_sort; }
|
||||
|
||||
void ItemReload(const QPersistentModelIndex &idx, const Song &old_metadata, const bool metadata_edit);
|
||||
|
||||
public slots:
|
||||
void set_current_row(const int i, const Playlist::AutoScroll autoscroll = Playlist::AutoScroll_Maybe, const bool is_stopping = false, const bool force_inform = false);
|
||||
void Paused();
|
||||
@ -332,7 +336,7 @@ class Playlist : public QAbstractListModel {
|
||||
void PlaylistLoaded();
|
||||
void CurrentSongChanged(Song metadata);
|
||||
void SongMetadataChanged(Song metadata);
|
||||
void EditingFinished(QModelIndex idx);
|
||||
void EditingFinished(const int playlist_id, QModelIndex idx);
|
||||
void PlayRequested(QModelIndex idx, Playlist::AutoScroll autoscroll);
|
||||
void MaybeAutoscroll(Playlist::AutoScroll autoscroll);
|
||||
|
||||
@ -375,15 +379,17 @@ class Playlist : public QAbstractListModel {
|
||||
void TracksDequeued();
|
||||
void TracksEnqueued(const QModelIndex&, const int begin, const int end);
|
||||
void QueueLayoutChanged();
|
||||
void SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx);
|
||||
void ItemReloadComplete(const QPersistentModelIndex &idx);
|
||||
void SongSaveComplete(TagReaderReply *reply, const QPersistentModelIndex &idx, const Song &old_metadata);
|
||||
void ItemReloadComplete(const QPersistentModelIndex &idx, const Song &old_metadata, const bool metadata_edit);
|
||||
void ItemsLoaded();
|
||||
void SongInsertVetoListenerDestroyed();
|
||||
void Save() const;
|
||||
|
||||
private:
|
||||
bool is_loading_;
|
||||
PlaylistFilter *proxy_;
|
||||
Queue *queue_;
|
||||
QTimer *timer_save_;
|
||||
|
||||
QList<QModelIndex> temp_dequeue_change_indexes_;
|
||||
|
||||
|
@ -133,7 +133,7 @@ class PlaylistManagerInterface : public QObject {
|
||||
|
||||
// Signals that one of manager's playlists has changed (new items, new ordering etc.) - the argument shows which.
|
||||
void PlaylistChanged(Playlist *playlist);
|
||||
void EditingFinished(QModelIndex idx);
|
||||
void EditingFinished(int playlist_id, QModelIndex idx);
|
||||
void PlayRequested(QModelIndex idx, Playlist::AutoScroll autoscroll);
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user