AlbumCoverManager: Queue album cover loading using timer

Helps reduce memory growth.
This commit is contained in:
Jonas Kvinge 2024-09-03 22:02:05 +02:00
parent 155485173b
commit de62552ad1
2 changed files with 53 additions and 15 deletions

View File

@ -23,6 +23,7 @@
#include <algorithm>
#include <utility>
#include <chrono>
#include <QObject>
#include <QMainWindow>
@ -93,6 +94,8 @@
#include "ui_albumcovermanager.h"
using namespace std::literals::chrono_literals;
namespace {
constexpr char kSettingsGroup[] = "CoverManager";
constexpr int kThumbnailSize = 120;
@ -105,6 +108,7 @@ AlbumCoverManager::AlbumCoverManager(Application *app, SharedPtr<CollectionBacke
app_(app),
collection_backend_(collection_backend),
album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
timer_album_cover_load_(new QTimer(this)),
filter_all_(nullptr),
filter_with_covers_(nullptr),
filter_without_covers_(nullptr),
@ -125,6 +129,10 @@ AlbumCoverManager::AlbumCoverManager(Application *app, SharedPtr<CollectionBacke
ui_->setupUi(this);
ui_->albums->set_cover_manager(this);
timer_album_cover_load_->setSingleShot(false);
timer_album_cover_load_->setInterval(10ms);
QObject::connect(timer_album_cover_load_, &QTimer::timeout, this, &AlbumCoverManager::LoadAlbumCovers);
// Icons
ui_->action_fetch->setIcon(IconLoader::Load(QStringLiteral("download")));
ui_->export_covers->setIcon(IconLoader::Load(QStringLiteral("document-save")));
@ -316,6 +324,7 @@ void AlbumCoverManager::CancelRequests() {
#else
app_->album_cover_loader()->CancelTasks(QSet<quint64>::fromList(cover_loading_tasks_.keys()));
#endif
cover_loading_pending_.clear();
cover_loading_tasks_.clear();
cover_save_tasks_.clear();
@ -346,7 +355,7 @@ void AlbumCoverManager::Reset() {
all_artists_ = new QListWidgetItem(all_artists_icon_, tr("All artists"), ui_->artists, All_Artists);
new AlbumItem(artist_icon_, tr("Various artists"), ui_->artists, Various_Artists);
QStringList artists(collection_backend_->GetAllArtistsWithAlbums());
QStringList artists = collection_backend_->GetAllArtistsWithAlbums();
std::stable_sort(artists.begin(), artists.end(), CompareNocase);
for (const QString &artist : std::as_const(artists)) {
@ -422,7 +431,7 @@ void AlbumCoverManager::ArtistChanged(QListWidgetItem *current) {
album_item->setData(Role_ArtUnset, album_info.art_unset);
if (album_info.art_embedded || !album_info.art_automatic.isEmpty() || !album_info.art_manual.isEmpty()) {
LoadAlbumCoverAsync(album_item);
QueueAlbumCoverLoad(album_item);
}
}
@ -431,6 +440,40 @@ void AlbumCoverManager::ArtistChanged(QListWidgetItem *current) {
}
void AlbumCoverManager::QueueAlbumCoverLoad(AlbumItem *album_item) {
cover_loading_pending_.enqueue(album_item);
if (!timer_album_cover_load_->isActive()) {
timer_album_cover_load_->start();
}
}
void AlbumCoverManager::LoadAlbumCovers() {
if (cover_loading_pending_.isEmpty()) {
if (timer_album_cover_load_->isActive()) {
timer_album_cover_load_->stop();
}
return;
}
LoadAlbumCoverAsync(cover_loading_pending_.dequeue());
}
void AlbumCoverManager::LoadAlbumCoverAsync(AlbumItem *album_item) {
AlbumCoverLoaderOptions cover_options(AlbumCoverLoaderOptions::Option::ScaledImage | AlbumCoverLoaderOptions::Option::PadScaledImage);
cover_options.types = cover_types_;
cover_options.desired_scaled_size = QSize(kThumbnailSize, kThumbnailSize);
cover_options.device_pixel_ratio = devicePixelRatioF();
quint64 cover_load_id = app_->album_cover_loader()->LoadImageAsync(cover_options, album_item->data(Role_ArtEmbedded).toBool(), album_item->data(Role_ArtAutomatic).toUrl(), album_item->data(Role_ArtManual).toUrl(), album_item->data(Role_ArtUnset).toBool(), album_item->urls.constFirst());
cover_loading_tasks_.insert(cover_load_id, album_item);
}
void AlbumCoverManager::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) {
if (!cover_loading_tasks_.contains(id)) return;
@ -1076,13 +1119,3 @@ void AlbumCoverManager::SaveEmbeddedCoverFinished(TagReaderReply *reply, AlbumIt
}
void AlbumCoverManager::LoadAlbumCoverAsync(AlbumItem *album_item) {
AlbumCoverLoaderOptions cover_options(AlbumCoverLoaderOptions::Option::ScaledImage | AlbumCoverLoaderOptions::Option::PadScaledImage);
cover_options.types = cover_types_;
cover_options.desired_scaled_size = QSize(kThumbnailSize, kThumbnailSize);
cover_options.device_pixel_ratio = devicePixelRatioF();
quint64 cover_load_id = app_->album_cover_loader()->LoadImageAsync(cover_options, album_item->data(Role_ArtEmbedded).toBool(), album_item->data(Role_ArtAutomatic).toUrl(), album_item->data(Role_ArtManual).toUrl(), album_item->data(Role_ArtUnset).toBool(), album_item->urls.constFirst());
cover_loading_tasks_.insert(cover_load_id, album_item);
}

View File

@ -32,6 +32,7 @@
#include <QListWidgetItem>
#include <QMap>
#include <QMultiMap>
#include <QQueue>
#include <QString>
#include <QImage>
#include <QIcon>
@ -44,7 +45,7 @@
#include "albumcoverchoicecontroller.h"
#include "coversearchstatistics.h"
class QWidget;
class QTimer;
class QMimeData;
class QMenu;
class QAction;
@ -136,6 +137,9 @@ class AlbumCoverManager : public QMainWindow {
Song AlbumItemAsSong(QListWidgetItem *list_widget_item) { return AlbumItemAsSong(static_cast<AlbumItem*>(list_widget_item)); }
static Song AlbumItemAsSong(AlbumItem *album_item);
void QueueAlbumCoverLoad(AlbumItem *album_item);
void LoadAlbumCoverAsync(AlbumItem *album_item);
void UpdateStatusText();
bool ShouldHide(const AlbumItem &album_item, const QString &filter, const HideCovers hide_covers) const;
void SaveAndSetCover(AlbumItem *album_item, const AlbumCoverImageResult &result);
@ -147,14 +151,13 @@ class AlbumCoverManager : public QMainWindow {
bool ItemHasCover(const AlbumItem &album_item) const;
void LoadAlbumCoverAsync(AlbumItem *album_item);
Q_SIGNALS:
void Error(const QString &error);
void AddToPlaylist(QMimeData *data);
private Q_SLOTS:
void ArtistChanged(QListWidgetItem *current);
void LoadAlbumCovers();
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
void UpdateFilter();
void FetchAlbumCovers();
@ -190,11 +193,13 @@ class AlbumCoverManager : public QMainWindow {
Application *app_;
SharedPtr<CollectionBackend> collection_backend_;
AlbumCoverChoiceController *album_cover_choice_controller_;
QTimer *timer_album_cover_load_;
QAction *filter_all_;
QAction *filter_with_covers_;
QAction *filter_without_covers_;
QQueue<AlbumItem*> cover_loading_pending_;
QMap<quint64, AlbumItem*> cover_loading_tasks_;
AlbumCoverFetcher *cover_fetcher_;