From b660287779833f295f27322b2d1a488c57fb4101 Mon Sep 17 00:00:00 2001 From: Jonas Kvinge Date: Thu, 6 Apr 2023 23:18:10 +0200 Subject: [PATCH] Use `std::shared_ptr`for `AlbumCoverLoaderResult` Reduces memory fragmentation with Qt 6 --- src/collection/collectionmodel.cpp | 12 +- src/collection/collectionmodel.h | 2 +- src/core/mainwindow.cpp | 46 +++++--- src/core/mainwindow.h | 4 +- src/core/metatypes.cpp | 1 + src/core/mpris2.cpp | 12 +- src/core/mpris2.h | 2 +- src/core/standarditemiconloader.cpp | 8 +- src/core/standarditemiconloader.h | 2 +- .../albumcoverchoicecontroller.cpp | 84 +++++++------- src/covermanager/albumcoverchoicecontroller.h | 18 +-- src/covermanager/albumcoverfetcher.cpp | 2 +- src/covermanager/albumcoverfetcher.h | 4 +- src/covermanager/albumcoverfetchersearch.cpp | 11 +- src/covermanager/albumcoverfetchersearch.h | 6 +- src/covermanager/albumcoverimageresult.h | 19 +++- src/covermanager/albumcoverloader.cpp | 105 ++++++++++-------- src/covermanager/albumcoverloader.h | 23 ++-- src/covermanager/albumcoverloaderoptions.h | 3 +- src/covermanager/albumcoverloaderresult.h | 22 +++- src/covermanager/albumcovermanager.cpp | 80 ++++++------- src/covermanager/albumcovermanager.h | 8 +- src/covermanager/albumcoversearcher.cpp | 32 +++--- src/covermanager/albumcoversearcher.h | 6 +- src/covermanager/coverfromurldialog.cpp | 16 +-- src/covermanager/coverfromurldialog.h | 4 +- src/covermanager/currentalbumcoverloader.cpp | 18 +-- src/covermanager/currentalbumcoverloader.h | 6 +- src/dialogs/edittagdialog.cpp | 53 ++++----- src/dialogs/edittagdialog.h | 8 +- src/internet/internetsearchview.cpp | 8 +- src/internet/internetsearchview.h | 2 +- src/playlist/playlist.cpp | 12 +- src/playlist/playlist.h | 2 +- src/playlist/playlistview.cpp | 6 +- src/playlist/playlistview.h | 2 +- src/radios/radiomodel.cpp | 6 +- src/radios/radiomodel.h | 2 +- 38 files changed, 363 insertions(+), 294 deletions(-) diff --git a/src/collection/collectionmodel.cpp b/src/collection/collectionmodel.cpp index d3120e69b..8c7614df0 100644 --- a/src/collection/collectionmodel.cpp +++ b/src/collection/collectionmodel.cpp @@ -655,7 +655,7 @@ QVariant CollectionModel::AlbumIcon(const QModelIndex &idx) { } -void CollectionModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) { +void CollectionModel::AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result) { if (!pending_art_.contains(id)) return; @@ -667,19 +667,21 @@ void CollectionModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderR pending_cache_keys_.remove(cache_key); + if (!result) return; + // Insert this image in the cache. - if (!result.success || result.image_scaled.isNull() || result.type == AlbumCoverLoaderResult::Type::ManuallyUnset) { + if (!result->success || result->image_scaled.isNull() || result->type == AlbumCoverLoaderResult::Type::ManuallyUnset) { // Set the no_cover image so we don't continually try to load art. QPixmapCache::insert(cache_key, no_cover_icon_); } else { QPixmap image_pixmap; - image_pixmap = QPixmap::fromImage(result.image_scaled); + image_pixmap = QPixmap::fromImage(result->image_scaled); QPixmapCache::insert(cache_key, image_pixmap); } // If we have a valid cover not already in the disk cache - if (use_disk_cache_ && sIconCache && result.success && !result.image_scaled.isNull()) { + if (use_disk_cache_ && sIconCache && result->success && !result->image_scaled.isNull()) { std::unique_ptr cached_img(sIconCache->data(QUrl(cache_key))); if (!cached_img) { QNetworkCacheMetaData item_metadata; @@ -687,7 +689,7 @@ void CollectionModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderR item_metadata.setUrl(QUrl(cache_key)); QIODevice *cache = sIconCache->prepare(item_metadata); if (cache) { - result.image_scaled.save(cache, "XPM"); + result->image_scaled.save(cache, "XPM"); sIconCache->insert(cache); } } diff --git a/src/collection/collectionmodel.h b/src/collection/collectionmodel.h index 65fa4dbde..4d90431c2 100644 --- a/src/collection/collectionmodel.h +++ b/src/collection/collectionmodel.h @@ -231,7 +231,7 @@ class CollectionModel : public SimpleTreeModel { // Called after ResetAsync void ResetAsyncQueryFinished(); - void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result); + void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result); private: // Provides some optimizations for loading the list of items in the root. diff --git a/src/core/mainwindow.cpp b/src/core/mainwindow.cpp index 854206b55..568481759 100644 --- a/src/core/mainwindow.cpp +++ b/src/core/mainwindow.cpp @@ -1296,7 +1296,7 @@ void MainWindow::MediaStopped() { song_playing_ = Song(); song_ = Song(); - album_cover_ = AlbumCoverImageResult(); + album_cover_.reset(); app_->scrobbler()->ClearPlaying(); @@ -3034,7 +3034,11 @@ void MainWindow::SearchForCover() { } void MainWindow::SaveCoverToFile() { - album_cover_choice_controller_->SaveCoverToFileManual(song_, album_cover_); + + if (album_cover_) { + album_cover_choice_controller_->SaveCoverToFileManual(song_, album_cover_); + } + } void MainWindow::UnsetCover() { @@ -3050,7 +3054,11 @@ void MainWindow::DeleteCover() { } void MainWindow::ShowCover() { - album_cover_choice_controller_->ShowCover(song_, album_cover_.image); + + if (album_cover_) { + album_cover_choice_controller_->ShowCover(song_, album_cover_->image); + } + } void MainWindow::SearchCoverAutomatically() { @@ -3059,24 +3067,29 @@ void MainWindow::SearchCoverAutomatically() { } -void MainWindow::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result) { +void MainWindow::AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result) { if (song != song_playing_) return; song_ = song; - album_cover_ = result.album_cover; - - emit AlbumCoverReady(song, result.album_cover.image); + if (result) { + album_cover_ = result->album_cover; + emit AlbumCoverReady(song, result->album_cover->image); + } + else { + album_cover_.reset(); + emit AlbumCoverReady(song, QImage()); + } const bool enable_change_art = song.is_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty(); - album_cover_choice_controller_->show_cover_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset); - album_cover_choice_controller_->cover_to_file_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset); + album_cover_choice_controller_->show_cover_action()->setEnabled(result && result->success && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset); + album_cover_choice_controller_->cover_to_file_action()->setEnabled(result && result->success && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset); album_cover_choice_controller_->cover_from_file_action()->setEnabled(enable_change_art); album_cover_choice_controller_->cover_from_url_action()->setEnabled(enable_change_art); album_cover_choice_controller_->search_for_cover_action()->setEnabled(app_->cover_providers()->HasAnyProviders() && enable_change_art); album_cover_choice_controller_->unset_cover_action()->setEnabled(enable_change_art && !song.has_manually_unset_cover()); album_cover_choice_controller_->clear_cover_action()->setEnabled(enable_change_art && !song.art_manual().isEmpty()); - album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && result.success && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset); + album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && result && result->success && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset); GetCoverAutomatically(); @@ -3085,13 +3098,12 @@ void MainWindow::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult void MainWindow::GetCoverAutomatically() { // Search for cover automatically? - bool search = - album_cover_choice_controller_->search_cover_auto_action()->isChecked() && - !song_.has_manually_unset_cover() && - !song_.art_automatic_is_valid() && - !song_.art_manual_is_valid() && - !song_.effective_albumartist().isEmpty() && - !song_.effective_album().isEmpty(); + const bool search = album_cover_choice_controller_->search_cover_auto_action()->isChecked() && + !song_.has_manually_unset_cover() && + !song_.art_automatic_is_valid() && + !song_.art_manual_is_valid() && + !song_.effective_albumartist().isEmpty() && + !song_.effective_album().isEmpty(); if (search) { emit SearchCoverInProgress(); diff --git a/src/core/mainwindow.h b/src/core/mainwindow.h index 3848ca2a6..4ecf949a1 100644 --- a/src/core/mainwindow.h +++ b/src/core/mainwindow.h @@ -258,7 +258,7 @@ class MainWindow : public QMainWindow, public PlatformInterface { void DeleteCover(); void ShowCover(); void SearchCoverAutomatically(); - void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result); + void AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result); void ScrobblingEnabledChanged(const bool value); void ScrobbleButtonVisibilityChanged(const bool value); @@ -391,7 +391,7 @@ class MainWindow : public QMainWindow, public PlatformInterface { Song song_; Song song_playing_; - AlbumCoverImageResult album_cover_; + AlbumCoverImageResultPtr album_cover_; bool exit_; int exit_count_; bool delete_files_; diff --git a/src/core/metatypes.cpp b/src/core/metatypes.cpp index a15882f30..d5929743e 100644 --- a/src/core/metatypes.cpp +++ b/src/core/metatypes.cpp @@ -123,6 +123,7 @@ void RegisterMetaTypes() { qRegisterMetaType("PlaylistSequence::RepeatMode"); qRegisterMetaType("PlaylistSequence::ShuffleMode"); qRegisterMetaType("AlbumCoverLoaderResult"); + qRegisterMetaType("AlbumCoverLoaderResultPtr"); qRegisterMetaType("AlbumCoverLoaderResult::Type"); qRegisterMetaType("CoverProviderSearchResult"); qRegisterMetaType("CoverProviderSearchResults"); diff --git a/src/core/mpris2.cpp b/src/core/mpris2.cpp index 19b304ea5..f744a6781 100644 --- a/src/core/mpris2.cpp +++ b/src/core/mpris2.cpp @@ -386,7 +386,9 @@ void Mpris2::CurrentSongChanged(const Song &song) { } // ... and we add the cover information later, when it's available. -void Mpris2::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result) { +void Mpris2::AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result) { + + if (!result) return; last_metadata_ = QVariantMap(); song.ToXesam(&last_metadata_); @@ -395,11 +397,11 @@ void Mpris2::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &re AddMetadata("mpris:trackid", current_track_id(), &last_metadata_); QUrl cover_url; - if (result.album_cover.cover_url.isValid() && result.album_cover.cover_url.isLocalFile() && QFile(result.album_cover.cover_url.toLocalFile()).exists()) { - cover_url = result.album_cover.cover_url; + if (result->album_cover->cover_url.isValid() && result->album_cover->cover_url.isLocalFile() && QFile(result->album_cover->cover_url.toLocalFile()).exists()) { + cover_url = result->album_cover->cover_url; } - else if (result.temp_cover_url.isValid() && result.temp_cover_url.isLocalFile()) { - cover_url = result.temp_cover_url; + else if (result->temp_cover_url.isValid() && result->temp_cover_url.isLocalFile()) { + cover_url = result->temp_cover_url; } else if (song.art_manual().isValid() && song.art_manual().isLocalFile() && song.art_manual().path() != Song::kManuallyUnsetCover && song.art_manual().path() != Song::kEmbeddedCover) { cover_url = song.art_manual(); diff --git a/src/core/mpris2.h b/src/core/mpris2.h index e632c4526..7785a2f43 100644 --- a/src/core/mpris2.h +++ b/src/core/mpris2.h @@ -202,7 +202,7 @@ class Mpris2 : public QObject { void PlaylistChanged(MprisPlaylist playlist); private slots: - void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result = AlbumCoverLoaderResult()); + void AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result = AlbumCoverLoaderResultPtr()); void EngineStateChanged(Engine::State newState); void VolumeChanged(); diff --git a/src/core/standarditemiconloader.cpp b/src/core/standarditemiconloader.cpp index f4689476e..7dc4e2dec 100644 --- a/src/core/standarditemiconloader.cpp +++ b/src/core/standarditemiconloader.cpp @@ -96,13 +96,15 @@ void StandardItemIconLoader::ModelReset() { } -void StandardItemIconLoader::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) { +void StandardItemIconLoader::AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result) { + + if (!pending_covers_.contains(id)) return; QStandardItem *item = pending_covers_.take(id); if (!item) return; - if (result.success && !result.image_scaled.isNull() && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset) { - item->setIcon(QIcon(QPixmap::fromImage(result.image_scaled))); + if (result && result->success && !result->image_scaled.isNull() && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset) { + item->setIcon(QIcon(QPixmap::fromImage(result->image_scaled))); } } diff --git a/src/core/standarditemiconloader.h b/src/core/standarditemiconloader.h index 0d135f71f..c6c3c691a 100644 --- a/src/core/standarditemiconloader.h +++ b/src/core/standarditemiconloader.h @@ -55,7 +55,7 @@ class StandardItemIconLoader : public QObject { void LoadIcon(const Song &song, QStandardItem *for_item); private slots: - void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result); + void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result); void RowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end); void ModelReset(); diff --git a/src/covermanager/albumcoverchoicecontroller.cpp b/src/covermanager/albumcoverchoicecontroller.cpp index bd06c11b9..66b243e0b 100644 --- a/src/covermanager/albumcoverchoicecontroller.cpp +++ b/src/covermanager/albumcoverchoicecontroller.cpp @@ -21,6 +21,8 @@ #include "config.h" +#include + #include #include #include @@ -168,27 +170,27 @@ QList AlbumCoverChoiceController::GetAllActions() { } -AlbumCoverImageResult AlbumCoverChoiceController::LoadImageFromFile(Song *song) { +AlbumCoverImageResultPtr AlbumCoverChoiceController::LoadImageFromFile(Song *song) { - if (!song->url().isLocalFile()) return AlbumCoverImageResult(); + if (!song->url().isLocalFile()) return AlbumCoverImageResultPtr(); QString cover_file = QFileDialog::getOpenFileName(this, tr("Load cover from disk"), GetInitialPathForFileDialog(*song, QString()), tr(kLoadImageFileFilter) + ";;" + tr(kAllFilesFilter)); - if (cover_file.isEmpty()) return AlbumCoverImageResult(); + if (cover_file.isEmpty()) return AlbumCoverImageResultPtr(); - AlbumCoverImageResult result; + AlbumCoverImageResultPtr result = std::make_shared(); QFile file(cover_file); if (file.open(QIODevice::ReadOnly)) { - result.image_data = file.readAll(); + result->image_data = file.readAll(); file.close(); - if (result.image_data.isEmpty()) { + if (result->image_data.isEmpty()) { qLog(Error) << "Cover file" << cover_file << "is empty."; emit Error(tr("Cover file %1 is empty.").arg(cover_file)); } else { - result.mime_type = Utilities::MimeTypeFromData(result.image_data); - result.image.loadFromData(result.image_data); - result.cover_url = QUrl::fromLocalFile(cover_file); + result->mime_type = Utilities::MimeTypeFromData(result->image_data); + result->image.loadFromData(result->image_data); + result->cover_url = QUrl::fromLocalFile(cover_file); } } else { @@ -229,7 +231,9 @@ QUrl AlbumCoverChoiceController::LoadCoverFromFile(Song *song) { } -void AlbumCoverChoiceController::SaveCoverToFileManual(const Song &song, const AlbumCoverImageResult &result) { +void AlbumCoverChoiceController::SaveCoverToFileManual(const Song &song, AlbumCoverImageResultPtr result) { + + if (!result) return; QString initial_file_name = "/"; @@ -256,10 +260,10 @@ void AlbumCoverChoiceController::SaveCoverToFileManual(const Song &song, const A fileinfo.setFile(save_filename); } - if (result.is_jpeg() && fileinfo.completeSuffix().compare("jpg", Qt::CaseInsensitive) == 0) { + if (result->is_jpeg() && fileinfo.completeSuffix().compare("jpg", Qt::CaseInsensitive) == 0) { QFile file(save_filename); if (file.open(QIODevice::WriteOnly)) { - if (file.write(result.image_data) <= 0) { + if (file.write(result->image_data) <= 0) { qLog(Error) << "Failed writing cover to file" << save_filename << file.errorString(); emit Error(tr("Failed writing cover to file %1: %2").arg(save_filename, file.errorString())); } @@ -271,7 +275,7 @@ void AlbumCoverChoiceController::SaveCoverToFileManual(const Song &song, const A } } else { - if (!result.image.save(save_filename)) { + if (!result->image.save(save_filename)) { qLog(Error) << "Failed writing cover to file" << save_filename; emit Error(tr("Failed writing cover to file %1.").arg(save_filename)); } @@ -305,9 +309,9 @@ QUrl AlbumCoverChoiceController::LoadCoverFromURL(Song *song) { if (!song->url().isLocalFile() || song->effective_albumartist().isEmpty() || song->album().isEmpty()) return QUrl(); - AlbumCoverImageResult result = LoadImageFromURL(); + AlbumCoverImageResultPtr result = LoadImageFromURL(); - if (result.image.isNull()) { + if (!result || result->image.isNull()) { return QUrl(); } else { @@ -316,7 +320,7 @@ QUrl AlbumCoverChoiceController::LoadCoverFromURL(Song *song) { } -AlbumCoverImageResult AlbumCoverChoiceController::LoadImageFromURL() { +AlbumCoverImageResultPtr AlbumCoverChoiceController::LoadImageFromURL() { if (!cover_from_url_dialog_) { cover_from_url_dialog_ = new CoverFromURLDialog(this); } @@ -329,8 +333,8 @@ QUrl AlbumCoverChoiceController::SearchForCover(Song *song) { if (!song->url().isLocalFile() || song->effective_albumartist().isEmpty() || song->album().isEmpty()) return QUrl(); // Get something sensible to stick in the search box - AlbumCoverImageResult result = SearchForImage(song); - if (result.is_valid()) { + AlbumCoverImageResultPtr result = SearchForImage(song); + if (result->is_valid()) { return SaveCoverAutomatic(song, result); } else { @@ -339,9 +343,9 @@ QUrl AlbumCoverChoiceController::SearchForCover(Song *song) { } -AlbumCoverImageResult AlbumCoverChoiceController::SearchForImage(Song *song) { +AlbumCoverImageResultPtr AlbumCoverChoiceController::SearchForImage(Song *song) { - if (!song->url().isLocalFile()) return AlbumCoverImageResult(); + if (!song->url().isLocalFile()) return AlbumCoverImageResultPtr(); QString album = song->effective_album(); album = album.remove(Song::kAlbumRemoveDisc).remove(Song::kAlbumRemoveMisc); @@ -377,7 +381,7 @@ bool AlbumCoverChoiceController::DeleteCover(Song *song, const bool manually_uns if (!song->url().isLocalFile() || song->effective_albumartist().isEmpty() || song->album().isEmpty()) return false; if (song->has_embedded_cover() && song->save_embedded_cover_supported()) { - SaveCoverEmbeddedAutomatic(*song, AlbumCoverImageResult()); + SaveCoverEmbeddedAutomatic(*song, std::make_shared()); } QString art_automatic; @@ -517,7 +521,7 @@ quint64 AlbumCoverChoiceController::SearchCoverAutomatically(const Song &song) { } -void AlbumCoverChoiceController::AlbumCoverFetched(const quint64 id, const AlbumCoverImageResult &result, const CoverSearchStatistics &statistics) { +void AlbumCoverChoiceController::AlbumCoverFetched(const quint64 id, AlbumCoverImageResultPtr result, const CoverSearchStatistics &statistics) { Q_UNUSED(statistics); @@ -526,7 +530,7 @@ void AlbumCoverChoiceController::AlbumCoverFetched(const quint64 id, const Album song = cover_fetching_tasks_.take(id); } - if (result.is_valid()) { + if (result && result->is_valid()) { SaveCoverAutomatic(&song, result); } @@ -596,7 +600,7 @@ void AlbumCoverChoiceController::SaveArtManualToSong(Song *song, const QUrl &art } -QUrl AlbumCoverChoiceController::SaveCoverToFileAutomatic(const Song *song, const AlbumCoverImageResult &result, const bool force_overwrite) { +QUrl AlbumCoverChoiceController::SaveCoverToFileAutomatic(const Song *song, AlbumCoverImageResultPtr result, const bool force_overwrite) { return SaveCoverToFileAutomatic(song->source(), song->effective_albumartist(), @@ -613,10 +617,12 @@ QUrl AlbumCoverChoiceController::SaveCoverToFileAutomatic(const Song::Source sou const QString &album, const QString &album_id, const QString &album_dir, - const AlbumCoverImageResult &result, + AlbumCoverImageResultPtr result, const bool force_overwrite) { - QString filepath = CoverUtils::CoverFilePath(cover_options_, source, artist, album, album_id, album_dir, result.cover_url, "jpg"); + if (!result) return QUrl(); + + QString filepath = CoverUtils::CoverFilePath(cover_options_, source, artist, album, album_id, album_dir, result->cover_url, "jpg"); if (filepath.isEmpty()) return QUrl(); QFile file(filepath); @@ -630,9 +636,9 @@ QUrl AlbumCoverChoiceController::SaveCoverToFileAutomatic(const Song::Source sou } QUrl cover_url; - if (result.is_jpeg()) { + if (result->is_jpeg()) { if (file.open(QIODevice::WriteOnly)) { - if (file.write(result.image_data) > 0) { + if (file.write(result->image_data) > 0) { cover_url = QUrl::fromLocalFile(filepath); } else { @@ -647,14 +653,16 @@ QUrl AlbumCoverChoiceController::SaveCoverToFileAutomatic(const Song::Source sou } } else { - if (result.image.save(filepath, "JPG")) cover_url = QUrl::fromLocalFile(filepath); + if (result->image.save(filepath, "JPG")) cover_url = QUrl::fromLocalFile(filepath); } return cover_url; } -void AlbumCoverChoiceController::SaveCoverEmbeddedAutomatic(const Song &song, const AlbumCoverImageResult &result) { +void AlbumCoverChoiceController::SaveCoverEmbeddedAutomatic(const Song &song, AlbumCoverImageResultPtr result) { + + if (!result) return; if (song.source() == Song::Source::Collection) { #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) @@ -669,13 +677,13 @@ void AlbumCoverChoiceController::SaveCoverEmbeddedAutomatic(const Song &song, co QList urls; urls.reserve(songs.count()); for (const Song &s : songs) urls << s.url(); - if (result.is_jpeg()) { - quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image_data); + if (result->is_jpeg()) { + quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image_data); QMutexLocker l(&mutex_cover_save_tasks_); cover_save_tasks_.insert(id, song); } else { - quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image); + quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image); QMutexLocker l(&mutex_cover_save_tasks_); cover_save_tasks_.insert(id, song); } @@ -683,11 +691,11 @@ void AlbumCoverChoiceController::SaveCoverEmbeddedAutomatic(const Song &song, co watcher->setFuture(future); } else { - if (result.is_jpeg()) { - app_->album_cover_loader()->SaveEmbeddedCoverAsync(song.url().toLocalFile(), result.image_data); + if (result->is_jpeg()) { + app_->album_cover_loader()->SaveEmbeddedCoverAsync(song.url().toLocalFile(), result->image_data); } else { - app_->album_cover_loader()->SaveEmbeddedCoverAsync(song.url().toLocalFile(), result.image); + app_->album_cover_loader()->SaveEmbeddedCoverAsync(song.url().toLocalFile(), result->image); } } @@ -775,7 +783,7 @@ QUrl AlbumCoverChoiceController::SaveCover(Song *song, const QDropEvent *e) { if (e->mimeData()->hasImage()) { QImage image = qvariant_cast(e->mimeData()->imageData()); if (!image.isNull()) { - return SaveCoverAutomatic(song, AlbumCoverImageResult(image)); + return SaveCoverAutomatic(song, std::make_shared(image)); } } @@ -783,7 +791,7 @@ QUrl AlbumCoverChoiceController::SaveCover(Song *song, const QDropEvent *e) { } -QUrl AlbumCoverChoiceController::SaveCoverAutomatic(Song *song, const AlbumCoverImageResult &result) { +QUrl AlbumCoverChoiceController::SaveCoverAutomatic(Song *song, AlbumCoverImageResultPtr result) { QUrl cover_url; switch(get_save_album_cover_type()) { diff --git a/src/covermanager/albumcoverchoicecontroller.h b/src/covermanager/albumcoverchoicecontroller.h index 0c1ee2a65..cbfe8b3c5 100644 --- a/src/covermanager/albumcoverchoicecontroller.h +++ b/src/covermanager/albumcoverchoicecontroller.h @@ -99,22 +99,22 @@ class AlbumCoverChoiceController : public QWidget { // Lets the user choose a cover from disk. If no cover will be chosen or the chosen cover will not be a proper image, this returns an empty string. // Otherwise, the path to the chosen cover will be returned. - AlbumCoverImageResult LoadImageFromFile(Song *song); + AlbumCoverImageResultPtr LoadImageFromFile(Song *song); QUrl LoadCoverFromFile(Song *song); // Shows a dialog that allows user to save the given image on disk. // The image is supposed to be the cover of the given song's album. - void SaveCoverToFileManual(const Song &song, const AlbumCoverImageResult &result); + void SaveCoverToFileManual(const Song &song, AlbumCoverImageResultPtr result); // Downloads the cover from an URL given by user. // This returns the downloaded image or null image if something went wrong for example when user cancelled the dialog. QUrl LoadCoverFromURL(Song *song); - AlbumCoverImageResult LoadImageFromURL(); + AlbumCoverImageResultPtr LoadImageFromURL(); // Lets the user choose a cover among all that have been found on last.fm. // Returns the chosen cover or null cover if user didn't choose anything. QUrl SearchForCover(Song *song); - AlbumCoverImageResult SearchForImage(Song *song); + AlbumCoverImageResultPtr SearchForImage(Song *song); // Returns a path which indicates that the cover has been unset manually. QUrl UnsetCover(Song *song, const bool clear_art_automatic = false); @@ -140,10 +140,10 @@ class AlbumCoverChoiceController : public QWidget { QUrl SaveCover(Song *song, const QDropEvent *e); // Saves the given image in album directory or cache as a cover for 'album artist' - 'album'. The method returns path of the image. - QUrl SaveCoverAutomatic(Song *song, const AlbumCoverImageResult &result); - QUrl SaveCoverToFileAutomatic(const Song *song, const AlbumCoverImageResult &result, const bool force_overwrite = false); - QUrl SaveCoverToFileAutomatic(const Song::Source source, const QString &artist, const QString &album, const QString &album_id, const QString &album_dir, const AlbumCoverImageResult &result, const bool force_overwrite = false); - void SaveCoverEmbeddedAutomatic(const Song &song, const AlbumCoverImageResult &result); + QUrl SaveCoverAutomatic(Song *song, AlbumCoverImageResultPtr result); + QUrl SaveCoverToFileAutomatic(const Song *song, AlbumCoverImageResultPtr result, const bool force_overwrite = false); + QUrl SaveCoverToFileAutomatic(const Song::Source source, const QString &artist, const QString &album, const QString &album_id, const QString &album_dir, AlbumCoverImageResultPtr result, const bool force_overwrite = false); + void SaveCoverEmbeddedAutomatic(const Song &song, AlbumCoverImageResultPtr result); void SaveCoverEmbeddedAutomatic(const Song &song, const QUrl &cover_url); void SaveCoverEmbeddedAutomatic(const Song &song, const QString &cover_filename); void SaveCoverEmbeddedAutomatic(const QList &urls, const QImage &image); @@ -154,7 +154,7 @@ class AlbumCoverChoiceController : public QWidget { void set_save_embedded_cover_override(const bool value) { save_embedded_cover_override_ = value; } private slots: - void AlbumCoverFetched(const quint64 id, const AlbumCoverImageResult &result, const CoverSearchStatistics &statistics); + void AlbumCoverFetched(const quint64 id, AlbumCoverImageResultPtr result, const CoverSearchStatistics &statistics); void SaveEmbeddedCoverAsyncFinished(quint64 id, const bool success, const bool cleared); signals: diff --git a/src/covermanager/albumcoverfetcher.cpp b/src/covermanager/albumcoverfetcher.cpp index 8a7fb7d8a..fe2bff927 100644 --- a/src/covermanager/albumcoverfetcher.cpp +++ b/src/covermanager/albumcoverfetcher.cpp @@ -150,7 +150,7 @@ void AlbumCoverFetcher::SingleSearchFinished(const quint64 request_id, const Cov } -void AlbumCoverFetcher::SingleCoverFetched(const quint64 request_id, const AlbumCoverImageResult &result) { +void AlbumCoverFetcher::SingleCoverFetched(const quint64 request_id, AlbumCoverImageResultPtr result) { if (!active_requests_.contains(request_id)) return; AlbumCoverFetcherSearch *search = active_requests_.take(request_id); diff --git a/src/covermanager/albumcoverfetcher.h b/src/covermanager/albumcoverfetcher.h index dbafd3e4a..50958eff9 100644 --- a/src/covermanager/albumcoverfetcher.h +++ b/src/covermanager/albumcoverfetcher.h @@ -118,12 +118,12 @@ class AlbumCoverFetcher : public QObject { void Clear(); signals: - void AlbumCoverFetched(quint64 request_id, AlbumCoverImageResult result, CoverSearchStatistics statistics); + void AlbumCoverFetched(quint64 request_id, AlbumCoverImageResultPtr result, CoverSearchStatistics statistics); void SearchFinished(quint64 request_id, CoverProviderSearchResults results, CoverSearchStatistics statistics); private slots: void SingleSearchFinished(const quint64, const CoverProviderSearchResults &results); - void SingleCoverFetched(const quint64, const AlbumCoverImageResult &result); + void SingleCoverFetched(const quint64, AlbumCoverImageResultPtr result); void StartRequests(); private: diff --git a/src/covermanager/albumcoverfetchersearch.cpp b/src/covermanager/albumcoverfetchersearch.cpp index cc2f6ae3e..fd2cb7d08 100644 --- a/src/covermanager/albumcoverfetchersearch.cpp +++ b/src/covermanager/albumcoverfetchersearch.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -256,7 +257,7 @@ void AlbumCoverFetcherSearch::AllProvidersFinished() { // No results? if (results_.isEmpty()) { statistics_.missing_images_++; - emit AlbumCoverFetched(request_.id, AlbumCoverImageResult()); + emit AlbumCoverFetched(request_.id, AlbumCoverImageResultPtr()); return; } @@ -332,7 +333,7 @@ void AlbumCoverFetcherSearch::ProviderCoverFetchFinished(QNetworkReply *reply) { } result.image_size = image.size(); result.score_quality = ScoreImage(image.size()); - candidate_images_.insert(result.score(), CandidateImage(result, AlbumCoverImageResult(result.image_url, mime_type, image_data, image))); + candidate_images_.insert(result.score(), CandidateImage(result, std::make_shared(result.image_url, mime_type, image_data, image))); qLog(Debug) << reply->url() << "from" << result.provider << "scored" << result.score(); } else { @@ -380,7 +381,7 @@ float AlbumCoverFetcherSearch::ScoreImage(const QSize size) { void AlbumCoverFetcherSearch::SendBestImage() { - AlbumCoverImageResult result; + AlbumCoverImageResultPtr result = std::make_shared(); if (!candidate_images_.isEmpty()) { QList candidate_images = candidate_images_.values(); @@ -391,8 +392,8 @@ void AlbumCoverFetcherSearch::SendBestImage() { statistics_.chosen_images_by_provider_[best_image.result.provider]++; statistics_.chosen_images_++; - statistics_.chosen_width_ += result.image.width(); - statistics_.chosen_height_ += result.image.height(); + statistics_.chosen_width_ += result->image.width(); + statistics_.chosen_height_ += result->image.height(); } else { statistics_.missing_images_++; diff --git a/src/covermanager/albumcoverfetchersearch.h b/src/covermanager/albumcoverfetchersearch.h index e575ebf5d..73e23c5a8 100644 --- a/src/covermanager/albumcoverfetchersearch.h +++ b/src/covermanager/albumcoverfetchersearch.h @@ -69,7 +69,7 @@ class AlbumCoverFetcherSearch : public QObject { void SearchFinished(quint64, CoverProviderSearchResults results); // It's the end of search and we've fetched a cover. - void AlbumCoverFetched(const quint64, AlbumCoverImageResult result); + void AlbumCoverFetched(const quint64, AlbumCoverImageResultPtr result); private slots: void ProviderSearchResults(const int id, const CoverProviderSearchResults &results); @@ -108,9 +108,9 @@ class AlbumCoverFetcherSearch : public QObject { // QMap is sorted by key (score). struct CandidateImage { - CandidateImage(const CoverProviderSearchResult &_result, const AlbumCoverImageResult &_album_cover) : result(_result), album_cover(_album_cover) {} + CandidateImage(const CoverProviderSearchResult &_result, AlbumCoverImageResultPtr _album_cover) : result(_result), album_cover(_album_cover) {} CoverProviderSearchResult result; - AlbumCoverImageResult album_cover; + AlbumCoverImageResultPtr album_cover; }; QMultiMap candidate_images_; diff --git a/src/covermanager/albumcoverimageresult.h b/src/covermanager/albumcoverimageresult.h index 35777aa26..35c03fe65 100644 --- a/src/covermanager/albumcoverimageresult.h +++ b/src/covermanager/albumcoverimageresult.h @@ -22,21 +22,24 @@ #include "config.h" +#include + #include #include #include #include #include -struct AlbumCoverImageResult { +class AlbumCoverImageResult { + public: explicit AlbumCoverImageResult(const QUrl &_cover_url = QUrl(), const QString &_mime_type = QString(), const QByteArray &_image_data = QByteArray(), - const QImage &_image = QImage()) : - cover_url(_cover_url), - mime_type(_mime_type), - image_data(_image_data), image(_image) {} - + const QImage &_image = QImage()) + : cover_url(_cover_url), + mime_type(_mime_type), + image_data(_image_data), + image(_image) {} explicit AlbumCoverImageResult(const QImage &_image) : image(_image) {} QUrl cover_url; @@ -48,6 +51,10 @@ struct AlbumCoverImageResult { bool is_jpeg() const { return mime_type == "image/jpeg" && !image_data.isEmpty(); } }; + +using AlbumCoverImageResultPtr = std::shared_ptr; + Q_DECLARE_METATYPE(AlbumCoverImageResult) +Q_DECLARE_METATYPE(AlbumCoverImageResultPtr) #endif // ALBUMCOVERIMAGERESULT_H diff --git a/src/covermanager/albumcoverloader.cpp b/src/covermanager/albumcoverloader.cpp index f803d176d..2bf537710 100644 --- a/src/covermanager/albumcoverloader.cpp +++ b/src/covermanager/albumcoverloader.cpp @@ -21,6 +21,8 @@ #include "config.h" +#include + #include #include #include @@ -81,8 +83,9 @@ void AlbumCoverLoader::Exit() { void AlbumCoverLoader::CancelTask(const quint64 id) { QMutexLocker l(&mutex_load_image_async_); - for (QQueue::iterator it = tasks_.begin(); it != tasks_.end(); ++it) { - if (it->id == id) { + for (QQueue::iterator it = tasks_.begin(); it != tasks_.end(); ++it) { + TaskPtr task = *it; + if (task->id == id) { tasks_.erase(it); // clazy:exclude=strict-iterators break; } @@ -93,8 +96,9 @@ void AlbumCoverLoader::CancelTask(const quint64 id) { void AlbumCoverLoader::CancelTasks(const QSet &ids) { QMutexLocker l(&mutex_load_image_async_); - for (QQueue::iterator it = tasks_.begin(); it != tasks_.end();) { - if (ids.contains(it->id)) { + for (QQueue::iterator it = tasks_.begin(); it != tasks_.end();) { + TaskPtr task = *it; + if (ids.contains(task->id)) { it = tasks_.erase(it); // clazy:exclude=strict-iterators } else { @@ -106,10 +110,11 @@ void AlbumCoverLoader::CancelTasks(const QSet &ids) { quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, const Song &song) { - Task task; - task.options = options; - task.song = song; - task.state = State::Manual; + TaskPtr task = std::make_shared(); + task->options = options; + task->song = song; + task->state = State::Manual; + task->album_cover = std::make_shared(); return EnqueueTask(task); @@ -122,20 +127,21 @@ quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, song.set_art_automatic(art_automatic); song.set_art_manual(art_manual); - Task task; - task.options = options; - task.song = song; - task.state = State::Manual; + TaskPtr task = std::make_shared(); + task->options = options; + task->song = song; + task->state = State::Manual; + task->album_cover = std::make_shared(); return EnqueueTask(task); } -quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, const AlbumCoverImageResult &album_cover) { +quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, AlbumCoverImageResultPtr album_cover) { - Task task; - task.options = options; - task.album_cover = album_cover; + TaskPtr task = std::make_shared(); + task->options = options; + task->album_cover = album_cover; return EnqueueTask(task); @@ -143,25 +149,26 @@ quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, const QImage &image) { - Task task; - task.options = options; - task.album_cover.image = image; + TaskPtr task = std::make_shared(); + task->options = options; + task->album_cover = std::make_shared(); + task->album_cover->image = image; return EnqueueTask(task); } -quint64 AlbumCoverLoader::EnqueueTask(Task &task) { +quint64 AlbumCoverLoader::EnqueueTask(TaskPtr task) { { QMutexLocker l(&mutex_load_image_async_); - task.id = load_image_async_id_++; + task->id = load_image_async_id_++; tasks_.enqueue(task); } QMetaObject::invokeMethod(this, "ProcessTasks", Qt::QueuedConnection); - return task.id; + return task->id; } @@ -169,19 +176,19 @@ void AlbumCoverLoader::ProcessTasks() { while (!stop_requested_) { // Get the next task - Task task; + TaskPtr task; { QMutexLocker l(&mutex_load_image_async_); if (tasks_.isEmpty()) return; task = tasks_.dequeue(); } - ProcessTask(&task); + ProcessTask(task); } } -void AlbumCoverLoader::ProcessTask(Task *task) { +void AlbumCoverLoader::ProcessTask(TaskPtr task) { TryLoadResult result = TryLoadImage(task); if (result.started_async) { @@ -190,16 +197,16 @@ void AlbumCoverLoader::ProcessTask(Task *task) { } if (result.loaded_success) { - result.album_cover.mime_type = Utilities::MimeTypeFromData(result.album_cover.image_data); + result.album_cover->mime_type = Utilities::MimeTypeFromData(result.album_cover->image_data); QImage image_scaled; QImage image_thumbnail; if (task->options.get_image_ && task->options.scale_output_image_) { - image_scaled = ImageUtils::ScaleAndPad(result.album_cover.image, task->options.scale_output_image_, task->options.pad_output_image_, task->options.desired_height_); + image_scaled = ImageUtils::ScaleAndPad(result.album_cover->image, task->options.scale_output_image_, task->options.pad_output_image_, task->options.desired_height_); } if (task->options.get_image_ && task->options.create_thumbnail_) { - image_thumbnail = ImageUtils::CreateThumbnail(result.album_cover.image, task->options.pad_thumbnail_image_, task->options.thumbnail_size_); + image_thumbnail = ImageUtils::CreateThumbnail(result.album_cover->image, task->options.pad_thumbnail_image_, task->options.thumbnail_size_); } - emit AlbumCoverLoaded(task->id, AlbumCoverLoaderResult(result.loaded_success, result.type, result.album_cover, image_scaled, image_thumbnail, task->art_updated)); + emit AlbumCoverLoaded(task->id, std::make_shared(result.loaded_success, result.type, result.album_cover, image_scaled, image_thumbnail, task->art_updated)); return; } @@ -207,7 +214,7 @@ void AlbumCoverLoader::ProcessTask(Task *task) { } -void AlbumCoverLoader::NextState(Task *task) { +void AlbumCoverLoader::NextState(TaskPtr task) { if (task->state == State::Manual) { // Try the automatic one next @@ -216,15 +223,15 @@ void AlbumCoverLoader::NextState(Task *task) { } else { // Give up - emit AlbumCoverLoaded(task->id, AlbumCoverLoaderResult(false, AlbumCoverLoaderResult::Type::None, AlbumCoverImageResult(task->options.default_output_image_), task->options.default_scaled_image_, task->options.default_thumbnail_image_, task->art_updated)); + emit AlbumCoverLoaded(task->id, std::make_shared(false, AlbumCoverLoaderResult::Type::None, std::make_shared(task->options.default_output_image_), task->options.default_scaled_image_, task->options.default_thumbnail_image_, task->art_updated)); } } -AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(Task *task) { +AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(TaskPtr task) { // Only scale and pad. - if (task->album_cover.is_valid()) { + if (task->album_cover->is_valid()) { return TryLoadResult(false, true, AlbumCoverLoaderResult::Type::Embedded, task->album_cover); } @@ -263,17 +270,17 @@ AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(Task *task) { if (!cover_url.isEmpty() && !cover_url.path().isEmpty()) { if (cover_url.path() == Song::kManuallyUnsetCover) { - return TryLoadResult(false, true, AlbumCoverLoaderResult::Type::ManuallyUnset, AlbumCoverImageResult(cover_url, QString(), QByteArray(), task->options.default_output_image_)); + return TryLoadResult(false, true, AlbumCoverLoaderResult::Type::ManuallyUnset, std::make_shared(cover_url, QString(), QByteArray(), task->options.default_output_image_)); } else if (cover_url.path() == Song::kEmbeddedCover && task->song.url().isLocalFile()) { QByteArray image_data = TagReaderClient::Instance()->LoadEmbeddedArtBlocking(task->song.url().toLocalFile()); if (!image_data.isEmpty()) { QImage image; if (!image_data.isEmpty() && task->options.get_image_ && image.loadFromData(image_data)) { - return TryLoadResult(false, !image.isNull(), AlbumCoverLoaderResult::Type::Embedded, AlbumCoverImageResult(cover_url, QString(), image_data, image)); + return TryLoadResult(false, !image.isNull(), AlbumCoverLoaderResult::Type::Embedded, std::make_shared(cover_url, QString(), image_data, image)); } else { - return TryLoadResult(false, !image_data.isEmpty(), AlbumCoverLoaderResult::Type::Embedded, AlbumCoverImageResult(cover_url, QString(), image_data, image)); + return TryLoadResult(false, !image_data.isEmpty(), AlbumCoverLoaderResult::Type::Embedded, std::make_shared(cover_url, QString(), image_data, image)); } } } @@ -286,10 +293,10 @@ AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(Task *task) { file.close(); QImage image; if (!image_data.isEmpty() && task->options.get_image_ && image.loadFromData(image_data)) { - return TryLoadResult(false, !image.isNull(), type, AlbumCoverImageResult(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image)); + return TryLoadResult(false, !image.isNull(), type, std::make_shared(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image)); } else { - return TryLoadResult(false, !image_data.isEmpty(), type, AlbumCoverImageResult(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image)); + return TryLoadResult(false, !image_data.isEmpty(), type, std::make_shared(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image)); } } else { @@ -308,10 +315,10 @@ AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(Task *task) { file.close(); QImage image; if (!image_data.isEmpty() && task->options.get_image_ && image.loadFromData(image_data)) { - return TryLoadResult(false, !image.isNull(), type, AlbumCoverImageResult(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image)); + return TryLoadResult(false, !image.isNull(), type, std::make_shared(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image)); } else { - return TryLoadResult(false, !image_data.isEmpty(), type, AlbumCoverImageResult(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image)); + return TryLoadResult(false, !image_data.isEmpty(), type, std::make_shared(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image)); } } else { @@ -329,12 +336,12 @@ AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(Task *task) { QNetworkReply *reply = network_->get(request); QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, cover_url]() { RemoteFetchFinished(reply, cover_url); }); - remote_tasks_.insert(reply, *task); - return TryLoadResult(true, false, type, AlbumCoverImageResult(cover_url)); + remote_tasks_.insert(reply, task); + return TryLoadResult(true, false, type, std::make_shared(cover_url)); } } - return TryLoadResult(false, false, AlbumCoverLoaderResult::Type::None, AlbumCoverImageResult(cover_url, QString(), QByteArray(), task->options.default_output_image_)); + return TryLoadResult(false, false, AlbumCoverLoaderResult::Type::None, std::make_shared(cover_url, QString(), QByteArray(), task->options.default_output_image_)); } @@ -343,12 +350,12 @@ void AlbumCoverLoader::RemoteFetchFinished(QNetworkReply *reply, const QUrl &cov reply->deleteLater(); if (!remote_tasks_.contains(reply)) return; - Task task = remote_tasks_.take(reply); + TaskPtr task = remote_tasks_.take(reply); // Handle redirects. QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute); if (redirect.isValid()) { - if (++task.redirects > kMaxRedirects) { + if (++task->redirects > kMaxRedirects) { return; // Give up. } QNetworkRequest request = reply->request(); @@ -369,9 +376,9 @@ void AlbumCoverLoader::RemoteFetchFinished(QNetworkReply *reply, const QUrl &cov if (image.loadFromData(image_data)) { QImage image_scaled; QImage image_thumbnail; - if (task.options.scale_output_image_) image_scaled = ImageUtils::ScaleAndPad(image, task.options.scale_output_image_, task.options.pad_output_image_, task.options.desired_height_); - if (task.options.create_thumbnail_) image_thumbnail = ImageUtils::CreateThumbnail(image, task.options.pad_thumbnail_image_, task.options.thumbnail_size_); - emit AlbumCoverLoaded(task.id, AlbumCoverLoaderResult(true, task.type, AlbumCoverImageResult(cover_url, mime_type, (task.options.get_image_data_ ? image_data : QByteArray()), image), image_scaled, image_thumbnail, task.art_updated)); + if (task->options.scale_output_image_) image_scaled = ImageUtils::ScaleAndPad(image, task->options.scale_output_image_, task->options.pad_output_image_, task->options.desired_height_); + if (task->options.create_thumbnail_) image_thumbnail = ImageUtils::CreateThumbnail(image, task->options.pad_thumbnail_image_, task->options.thumbnail_size_); + emit AlbumCoverLoaded(task->id, std::make_shared(true, task->type, std::make_shared(cover_url, mime_type, (task->options.get_image_data_ ? image_data : QByteArray()), image), image_scaled, image_thumbnail, task->art_updated)); return; } else { @@ -382,7 +389,7 @@ void AlbumCoverLoader::RemoteFetchFinished(QNetworkReply *reply, const QUrl &cov qLog(Error) << "Unable to get album cover" << cover_url << reply->error() << reply->errorString(); } - NextState(&task); + NextState(task); } diff --git a/src/covermanager/albumcoverloader.h b/src/covermanager/albumcoverloader.h index fb2de75d6..a9fe338a3 100644 --- a/src/covermanager/albumcoverloader.h +++ b/src/covermanager/albumcoverloader.h @@ -64,7 +64,7 @@ class AlbumCoverLoader : public QObject { quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const Song &song); quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const QUrl &art_automatic, const QUrl &art_manual, const QUrl &song_url = QUrl(), const Song::Source song_source = Song::Source::Unknown); - quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const AlbumCoverImageResult &album_cover); + quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, AlbumCoverImageResultPtr album_cover); quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const QImage &image); void CancelTask(const quint64 id); @@ -79,7 +79,7 @@ class AlbumCoverLoader : public QObject { signals: void ExitFinished(); - void AlbumCoverLoaded(quint64 id, AlbumCoverLoaderResult result); + void AlbumCoverLoaded(quint64 id, AlbumCoverLoaderResultPtr result); void SaveEmbeddedCoverAsyncFinished(quint64 id, bool success, bool cleared); protected slots: @@ -105,18 +105,19 @@ class AlbumCoverLoader : public QObject { quint64 id; Song song; - AlbumCoverImageResult album_cover; + AlbumCoverImageResultPtr album_cover; State state; AlbumCoverLoaderResult::Type type; bool art_updated; int redirects; }; + using TaskPtr = std::shared_ptr; struct TryLoadResult { explicit TryLoadResult(const bool _started_async = false, const bool _loaded_success = false, const AlbumCoverLoaderResult::Type _type = AlbumCoverLoaderResult::Type::None, - const AlbumCoverImageResult &_album_cover = AlbumCoverImageResult()) : + AlbumCoverImageResultPtr _album_cover = AlbumCoverImageResultPtr()) : started_async(_started_async), loaded_success(_loaded_success), type(_type), @@ -126,20 +127,20 @@ class AlbumCoverLoader : public QObject { bool loaded_success; AlbumCoverLoaderResult::Type type; - AlbumCoverImageResult album_cover; + AlbumCoverImageResultPtr album_cover; }; - quint64 EnqueueTask(Task &task); - void ProcessTask(Task *task); - void NextState(Task *task); - TryLoadResult TryLoadImage(Task *task); + quint64 EnqueueTask(TaskPtr task); + void ProcessTask(TaskPtr task); + void NextState(TaskPtr task); + TryLoadResult TryLoadImage(TaskPtr task); bool stop_requested_; QMutex mutex_load_image_async_; QMutex mutex_save_image_async_; - QQueue tasks_; - QHash remote_tasks_; + QQueue tasks_; + QHash remote_tasks_; quint64 load_image_async_id_; quint64 save_image_async_id_; diff --git a/src/covermanager/albumcoverloaderoptions.h b/src/covermanager/albumcoverloaderoptions.h index 02f028ce2..fae098f73 100644 --- a/src/covermanager/albumcoverloaderoptions.h +++ b/src/covermanager/albumcoverloaderoptions.h @@ -27,7 +27,8 @@ #include #include -struct AlbumCoverLoaderOptions { +class AlbumCoverLoaderOptions { + public: explicit AlbumCoverLoaderOptions() : get_image_data_(true), get_image_(true), diff --git a/src/covermanager/albumcoverloaderresult.h b/src/covermanager/albumcoverloaderresult.h index ed62b8934..e4e9909a2 100644 --- a/src/covermanager/albumcoverloaderresult.h +++ b/src/covermanager/albumcoverloaderresult.h @@ -22,12 +22,15 @@ #include "config.h" +#include + #include #include #include "albumcoverimageresult.h" -struct AlbumCoverLoaderResult { +class AlbumCoverLoaderResult { + public: enum class Type { None, @@ -40,7 +43,7 @@ struct AlbumCoverLoaderResult { explicit AlbumCoverLoaderResult(const bool _success = false, const Type _type = Type::None, - const AlbumCoverImageResult &_album_cover = AlbumCoverImageResult(), + AlbumCoverImageResultPtr _album_cover = AlbumCoverImageResultPtr(), const QImage &_image_scaled = QImage(), const QImage &_image_thumbnail = QImage(), const bool _updated = false) : @@ -49,11 +52,17 @@ struct AlbumCoverLoaderResult { album_cover(_album_cover), image_scaled(_image_scaled), image_thumbnail(_image_thumbnail), - updated(_updated) {} + updated(_updated) { + + if (!_album_cover) { + _album_cover = std::make_shared(); + } + + } bool success; Type type; - AlbumCoverImageResult album_cover; + AlbumCoverImageResultPtr album_cover; QImage image_scaled; QImage image_thumbnail; bool updated; @@ -62,4 +71,9 @@ struct AlbumCoverLoaderResult { }; +using AlbumCoverLoaderResultPtr = std::shared_ptr; + +Q_DECLARE_METATYPE(AlbumCoverLoaderResult) +Q_DECLARE_METATYPE(AlbumCoverLoaderResultPtr) + #endif // ALBUMCOVERLOADERRESULT_H diff --git a/src/covermanager/albumcovermanager.cpp b/src/covermanager/albumcovermanager.cpp index 11f41204f..431d5f0fb 100644 --- a/src/covermanager/albumcovermanager.cpp +++ b/src/covermanager/albumcovermanager.cpp @@ -443,21 +443,21 @@ void AlbumCoverManager::ArtistChanged(QListWidgetItem *current) { } -void AlbumCoverManager::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) { +void AlbumCoverManager::AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result) { if (!cover_loading_tasks_.contains(id)) return; AlbumItem *item = cover_loading_tasks_.take(id); - if (!result.success || result.image_scaled.isNull() || result.type == AlbumCoverLoaderResult::Type::ManuallyUnset) { + if (!result || !result->success || result->image_scaled.isNull() || result->type == AlbumCoverLoaderResult::Type::ManuallyUnset) { item->setIcon(icon_nocover_item_); } else { - item->setIcon(QPixmap::fromImage(result.image_scaled)); + item->setIcon(QPixmap::fromImage(result->image_scaled)); } - //item->setData(Role_Image, result.image_original); - //item->setData(Role_ImageData, result.image_data); + //item->setData(Role_Image, result->image_original); + //item->setData(Role_ImageData, result->image_data); UpdateFilter(); @@ -547,12 +547,12 @@ void AlbumCoverManager::FetchAlbumCovers() { } -void AlbumCoverManager::AlbumCoverFetched(const quint64 id, const AlbumCoverImageResult &result, const CoverSearchStatistics &statistics) { +void AlbumCoverManager::AlbumCoverFetched(const quint64 id, AlbumCoverImageResultPtr result, const CoverSearchStatistics &statistics) { if (!cover_fetching_tasks_.contains(id)) return; AlbumItem *item = cover_fetching_tasks_.take(id); - if (!result.image.isNull()) { + if (result && !result->image.isNull()) { SaveAndSetCover(item, result); } @@ -709,8 +709,8 @@ void AlbumCoverManager::LoadCoverFromFile() { Song song = GetSingleSelectionAsSong(); if (!song.is_valid()) return; - AlbumCoverImageResult result = album_cover_choice_controller_->LoadImageFromFile(&song); - if (!result.image.isNull()) { + AlbumCoverImageResultPtr result = album_cover_choice_controller_->LoadImageFromFile(&song); + if (result || !result->image.isNull()) { SaveImageToAlbums(&song, result); } @@ -721,32 +721,32 @@ void AlbumCoverManager::SaveCoverToFile() { Song song = GetSingleSelectionAsSong(); if (!song.is_valid() || song.has_manually_unset_cover()) return; - AlbumCoverImageResult result; + AlbumCoverImageResultPtr result = std::make_shared(); // Load the image from disk if (!song.art_manual().isEmpty() && !song.has_manually_unset_cover() && song.art_manual().isLocalFile() && QFile::exists(song.art_manual().toLocalFile())) { - result.image_data = Utilities::ReadDataFromFile(song.art_manual().toLocalFile()); + result->image_data = Utilities::ReadDataFromFile(song.art_manual().toLocalFile()); } else if (!song.art_manual().isEmpty() && !song.art_manual().path().isEmpty() && song.art_manual().scheme().isEmpty() && QFile::exists(song.art_manual().path())) { - result.image_data = Utilities::ReadDataFromFile(song.art_manual().path()); + result->image_data = Utilities::ReadDataFromFile(song.art_manual().path()); } else if (song.has_embedded_cover()) { - result.image_data = TagReaderClient::Instance()->LoadEmbeddedArtBlocking(song.url().toLocalFile()); + result->image_data = TagReaderClient::Instance()->LoadEmbeddedArtBlocking(song.url().toLocalFile()); } else if (!song.art_automatic().isEmpty() && song.art_automatic().isLocalFile() && QFile::exists(song.art_automatic().toLocalFile())) { - result.image_data = Utilities::ReadDataFromFile(song.art_automatic().toLocalFile()); + result->image_data = Utilities::ReadDataFromFile(song.art_automatic().toLocalFile()); } else if (!song.art_automatic().isEmpty() && !song.art_automatic().path().isEmpty() && song.art_automatic().scheme().isEmpty() && QFile::exists(song.art_automatic().path())) { - result.image_data = Utilities::ReadDataFromFile(song.art_automatic().path()); + result->image_data = Utilities::ReadDataFromFile(song.art_automatic().path()); } - if (!result.is_valid()) return; + if (!result->is_valid()) return; - result.mime_type = Utilities::MimeTypeFromData(result.image_data); + result->mime_type = Utilities::MimeTypeFromData(result->image_data); - if (!result.image_data.isEmpty()) { - result.image.loadFromData(result.image_data); + if (!result->image_data.isEmpty()) { + result->image.loadFromData(result->image_data); } album_cover_choice_controller_->SaveCoverToFileManual(song, result); @@ -758,8 +758,8 @@ void AlbumCoverManager::LoadCoverFromURL() { Song song = GetSingleSelectionAsSong(); if (!song.is_valid()) return; - AlbumCoverImageResult result = album_cover_choice_controller_->LoadImageFromURL(); - if (result.is_valid()) { + AlbumCoverImageResultPtr result = album_cover_choice_controller_->LoadImageFromURL(); + if (result && result->is_valid()) { SaveImageToAlbums(&song, result); } @@ -770,16 +770,18 @@ void AlbumCoverManager::SearchForCover() { Song song = GetFirstSelectedAsSong(); if (!song.is_valid()) return; - AlbumCoverImageResult result = album_cover_choice_controller_->SearchForImage(&song); - if (result.is_valid()) { + AlbumCoverImageResultPtr result = album_cover_choice_controller_->SearchForImage(&song); + if (result && result->is_valid()) { SaveImageToAlbums(&song, result); } } -void AlbumCoverManager::SaveImageToAlbums(Song *song, const AlbumCoverImageResult &result) { +void AlbumCoverManager::SaveImageToAlbums(Song *song, AlbumCoverImageResultPtr result) { - QUrl cover_url = result.cover_url; + if (!result) return; + + QUrl cover_url = result->cover_url; switch (album_cover_choice_controller_->get_save_album_cover_type()) { case CoverOptions::CoverType::Cache: case CoverOptions::CoverType::Album: @@ -815,11 +817,11 @@ void AlbumCoverManager::SaveImageToAlbums(Song *song, const AlbumCoverImageResul if (album_cover_choice_controller_->get_save_album_cover_type() == CoverOptions::CoverType::Embedded && !urls.isEmpty()) { quint64 id = -1; - if (result.is_jpeg()) { - id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image_data); + if (result->is_jpeg()) { + id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image_data); } else { - id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image); + id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image); } for (AlbumItem *album_item : album_items) { cover_save_tasks_.insert(id, album_item); @@ -963,7 +965,9 @@ void AlbumCoverManager::LoadSelectedToPlaylist() { } -void AlbumCoverManager::SaveAndSetCover(AlbumItem *item, const AlbumCoverImageResult &result) { +void AlbumCoverManager::SaveAndSetCover(AlbumItem *item, AlbumCoverImageResultPtr result) { + + if (!result) return; const QString albumartist = item->data(Role_AlbumArtist).toString(); const QString album = item->data(Role_Album).toString(); @@ -972,25 +976,25 @@ void AlbumCoverManager::SaveAndSetCover(AlbumItem *item, const AlbumCoverImageRe const bool has_cue = !item->data(Role_CuePath).toString().isEmpty(); if (album_cover_choice_controller_->get_save_album_cover_type() == CoverOptions::CoverType::Embedded && Song::save_embedded_cover_supported(filetype) && !has_cue) { - if (result.is_jpeg()) { - quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image_data); + if (result->is_jpeg()) { + quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image_data); cover_save_tasks_.insert(id, item); } - else if (!result.image.isNull()) { - quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image); + else if (!result->image.isNull()) { + quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image); cover_save_tasks_.insert(id, item); } - else if (!result.cover_url.isEmpty() && result.cover_url.isLocalFile()) { - quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.cover_url.toLocalFile()); + else if (!result->cover_url.isEmpty() && result->cover_url.isLocalFile()) { + quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->cover_url.toLocalFile()); cover_save_tasks_.insert(id, item); } } else { QUrl cover_url; - if (!result.cover_url.isEmpty() && result.cover_url.isValid() && result.cover_url.isLocalFile()) { - cover_url = result.cover_url; + if (!result->cover_url.isEmpty() && result->cover_url.isValid() && result->cover_url.isLocalFile()) { + cover_url = result->cover_url; } - else if (!result.image_data.isEmpty() || !result.image.isNull()) { + else if (!result->image_data.isEmpty() || !result->image.isNull()) { cover_url = album_cover_choice_controller_->SaveCoverToFileAutomatic(Song::Source::Collection, albumartist, album, QString(), urls.first().adjusted(QUrl::RemoveFilename).path(), result, false); } diff --git a/src/covermanager/albumcovermanager.h b/src/covermanager/albumcovermanager.h index fce0f70af..8d06273f6 100644 --- a/src/covermanager/albumcovermanager.h +++ b/src/covermanager/albumcovermanager.h @@ -137,9 +137,9 @@ class AlbumCoverManager : public QMainWindow { void UpdateStatusText(); bool ShouldHide(const AlbumItem &item, const QString &filter, const HideCovers hide_covers) const; - void SaveAndSetCover(AlbumItem *item, const AlbumCoverImageResult &result); + void SaveAndSetCover(AlbumItem *item, AlbumCoverImageResultPtr result); - void SaveImageToAlbums(Song *song, const AlbumCoverImageResult &result); + void SaveImageToAlbums(Song *song, AlbumCoverImageResultPtr result); SongList GetSongsInAlbums(const QModelIndexList &indexes) const; SongMimeData *GetMimeDataForAlbums(const QModelIndexList &indexes) const; @@ -152,11 +152,11 @@ class AlbumCoverManager : public QMainWindow { private slots: void ArtistChanged(QListWidgetItem *current); - void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result); + void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result); void UpdateFilter(); void FetchAlbumCovers(); void ExportCovers(); - void AlbumCoverFetched(const quint64 id, const AlbumCoverImageResult &result, const CoverSearchStatistics &statistics); + void AlbumCoverFetched(const quint64 id, AlbumCoverImageResultPtr result, const CoverSearchStatistics &statistics); void CancelRequests(); // On the context menu diff --git a/src/covermanager/albumcoversearcher.cpp b/src/covermanager/albumcoversearcher.cpp index ef089a70e..2e99ec6d6 100644 --- a/src/covermanager/albumcoversearcher.cpp +++ b/src/covermanager/albumcoversearcher.cpp @@ -21,6 +21,8 @@ #include "config.h" +#include + #include #include #include @@ -161,7 +163,7 @@ void AlbumCoverSearcher::Init(AlbumCoverFetcher *fetcher) { } -AlbumCoverImageResult AlbumCoverSearcher::Exec(const QString &artist, const QString &album) { +AlbumCoverImageResultPtr AlbumCoverSearcher::Exec(const QString &artist, const QString &album) { ui_->artist->setText(artist); ui_->album->setText(album); @@ -171,16 +173,16 @@ AlbumCoverImageResult AlbumCoverSearcher::Exec(const QString &artist, const QStr Search(); } - if (exec() == QDialog::Rejected) return AlbumCoverImageResult(); + if (exec() == QDialog::Rejected) return AlbumCoverImageResultPtr(); QModelIndex selected = ui_->covers->currentIndex(); if (!selected.isValid() || !selected.data(Role_ImageFetchFinished).toBool()) - return AlbumCoverImageResult(); + return AlbumCoverImageResultPtr(); - AlbumCoverImageResult result; - result.image_data = selected.data(Role_ImageData).toByteArray(); - result.image = selected.data(Role_Image).value(); - result.mime_type = Utilities::MimeTypeFromData(result.image_data); + AlbumCoverImageResultPtr result = std::make_shared(); + result->image_data = selected.data(Role_ImageData).toByteArray(); + result->image = selected.data(Role_Image).value(); + result->mime_type = Utilities::MimeTypeFromData(result->image_data); return result; @@ -246,31 +248,31 @@ void AlbumCoverSearcher::SearchFinished(const quint64 id, const CoverProviderSea } -void AlbumCoverSearcher::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) { +void AlbumCoverSearcher::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResultPtr result) { if (!cover_loading_tasks_.contains(id)) return; QStandardItem *item = cover_loading_tasks_.take(id); if (cover_loading_tasks_.isEmpty()) ui_->busy->hide(); - if (!result.success || result.album_cover.image_data.isNull() || result.album_cover.image.isNull() || result.image_thumbnail.isNull()) { + if (!result || !result->success || result->album_cover->image_data == nullptr || result->album_cover->image_data.isNull() || result->album_cover->image.isNull() || result->image_thumbnail.isNull()) { model_->removeRow(item->row()); return; } - QPixmap pixmap = QPixmap::fromImage(result.image_thumbnail); + const QPixmap pixmap = QPixmap::fromImage(result->image_thumbnail); if (pixmap.isNull()) { model_->removeRow(item->row()); return; } - QIcon icon(pixmap); + const QIcon icon(pixmap); item->setData(true, Role_ImageFetchFinished); - item->setData(result.album_cover.image_data, Role_ImageData); - item->setData(result.album_cover.image, Role_Image); - item->setData(result.album_cover.image.width() * result.album_cover.image.height(), Role_ImageDimensions); - item->setData(result.album_cover.image.size(), Role_ImageSize); + item->setData(result->album_cover->image_data, Role_ImageData); + item->setData(result->album_cover->image, Role_Image); + item->setData(result->album_cover->image.width() * result->album_cover->image.height(), Role_ImageDimensions); + item->setData(result->album_cover->image.size(), Role_ImageSize); if (!icon.isNull()) item->setIcon(icon); } diff --git a/src/covermanager/albumcoversearcher.h b/src/covermanager/albumcoversearcher.h index 5e8fc82f2..9f157687f 100644 --- a/src/covermanager/albumcoversearcher.h +++ b/src/covermanager/albumcoversearcher.h @@ -83,12 +83,12 @@ class AlbumCoverSearcher : public QDialog { Role_ImageData, Role_Image, Role_ImageDimensions, - Role_ImageSize, + Role_ImageSize }; void Init(AlbumCoverFetcher *fetcher); - AlbumCoverImageResult Exec(const QString &artist, const QString &album); + AlbumCoverImageResultPtr Exec(const QString &artist, const QString &album); protected: void keyPressEvent(QKeyEvent*) override; @@ -96,7 +96,7 @@ class AlbumCoverSearcher : public QDialog { private slots: void Search(); void SearchFinished(const quint64 id, const CoverProviderSearchResults &results); - void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result); + void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result); void CoverDoubleClicked(const QModelIndex &idx); diff --git a/src/covermanager/coverfromurldialog.cpp b/src/covermanager/coverfromurldialog.cpp index ec8cdc2a1..5c6693b01 100644 --- a/src/covermanager/coverfromurldialog.cpp +++ b/src/covermanager/coverfromurldialog.cpp @@ -21,6 +21,8 @@ #include "config.h" +#include + #include #include #include @@ -49,11 +51,11 @@ CoverFromURLDialog::~CoverFromURLDialog() { delete ui_; } -AlbumCoverImageResult CoverFromURLDialog::Exec() { +AlbumCoverImageResultPtr CoverFromURLDialog::Exec() { // reset state ui_->url->setText(""); - last_album_cover_ = AlbumCoverImageResult(); + last_album_cover_.reset(); QClipboard *clipboard = QApplication::clipboard(); ui_->url->setText(clipboard->text()); @@ -87,12 +89,12 @@ void CoverFromURLDialog::LoadCoverFromURLFinished() { return; } - AlbumCoverImageResult result; - result.image_data = reply->readAll(); - result.image.loadFromData(result.image_data); - result.mime_type = Utilities::MimeTypeFromData(result.image_data); + AlbumCoverImageResultPtr result = std::make_shared(); + result->image_data = reply->readAll(); + result->image.loadFromData(result->image_data); + result->mime_type = Utilities::MimeTypeFromData(result->image_data); - if (!result.image.isNull()) { + if (!result->image.isNull()) { last_album_cover_ = result; QDialog::accept(); } diff --git a/src/covermanager/coverfromurldialog.h b/src/covermanager/coverfromurldialog.h index fc02d8b24..0386ba3ec 100644 --- a/src/covermanager/coverfromurldialog.h +++ b/src/covermanager/coverfromurldialog.h @@ -44,7 +44,7 @@ class CoverFromURLDialog : public QDialog { ~CoverFromURLDialog() override; // Opens the dialog. This returns an image found at the URL chosen by user or null image if the dialog got rejected. - AlbumCoverImageResult Exec(); + AlbumCoverImageResultPtr Exec(); private slots: void accept() override; @@ -54,7 +54,7 @@ class CoverFromURLDialog : public QDialog { Ui_CoverFromURLDialog *ui_; NetworkAccessManager *network_; - AlbumCoverImageResult last_album_cover_; + AlbumCoverImageResultPtr last_album_cover_; }; #endif // COVERFROMURLDIALOG_H diff --git a/src/covermanager/currentalbumcoverloader.cpp b/src/covermanager/currentalbumcoverloader.cpp index f48799b5f..42b8345ef 100644 --- a/src/covermanager/currentalbumcoverloader.cpp +++ b/src/covermanager/currentalbumcoverloader.cpp @@ -70,17 +70,17 @@ void CurrentAlbumCoverLoader::LoadAlbumCover(const Song &song) { } -void CurrentAlbumCoverLoader::TempAlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResult result) { +void CurrentAlbumCoverLoader::TempAlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result) { if (id != id_) return; id_ = 0; - if (!result.album_cover.image.isNull()) { + if (result && !result->album_cover->image.isNull()) { temp_cover_ = std::make_unique(temp_file_pattern_); temp_cover_->setAutoRemove(true); if (temp_cover_->open()) { - if (result.album_cover.image.save(temp_cover_->fileName(), "JPEG")) { - result.temp_cover_url = QUrl::fromLocalFile(temp_cover_->fileName()); + if (result->album_cover->image.save(temp_cover_->fileName(), "JPEG")) { + result->temp_cover_url = QUrl::fromLocalFile(temp_cover_->fileName()); } else { qLog(Error) << "Failed to save cover image to" << temp_cover_->fileName() << temp_cover_->errorString(); @@ -92,11 +92,11 @@ void CurrentAlbumCoverLoader::TempAlbumCoverLoaded(const quint64 id, AlbumCoverL } QUrl thumbnail_url; - if (!result.image_thumbnail.isNull()) { + if (result && !result->image_thumbnail.isNull()) { temp_cover_thumbnail_ = std::make_unique(temp_file_pattern_); temp_cover_thumbnail_->setAutoRemove(true); if (temp_cover_thumbnail_->open()) { - if (result.image_thumbnail.save(temp_cover_thumbnail_->fileName(), "JPEG")) { + if (result->image_thumbnail.save(temp_cover_thumbnail_->fileName(), "JPEG")) { thumbnail_url = QUrl::fromLocalFile(temp_cover_thumbnail_->fileName()); } else { @@ -108,11 +108,11 @@ void CurrentAlbumCoverLoader::TempAlbumCoverLoaded(const quint64 id, AlbumCoverL } } - if (result.updated) { - last_song_.set_art_manual(result.album_cover.cover_url); + if (result && result->updated) { + last_song_.set_art_manual(result->album_cover->cover_url); } emit AlbumCoverLoaded(last_song_, result); - emit ThumbnailLoaded(last_song_, thumbnail_url, result.image_thumbnail); + emit ThumbnailLoaded(last_song_, thumbnail_url, result->image_thumbnail); } diff --git a/src/covermanager/currentalbumcoverloader.h b/src/covermanager/currentalbumcoverloader.h index 07a2298bb..5296a2f0e 100644 --- a/src/covermanager/currentalbumcoverloader.h +++ b/src/covermanager/currentalbumcoverloader.h @@ -52,11 +52,11 @@ class CurrentAlbumCoverLoader : public QObject { void LoadAlbumCover(const Song &song); signals: - void AlbumCoverLoaded(Song song, AlbumCoverLoaderResult result); - void ThumbnailLoaded(Song song, QUrl thumbnail_uri, QImage image); + void AlbumCoverLoaded(Song song, AlbumCoverLoaderResultPtr result); + void ThumbnailLoaded(Song song, QUrl thumbnail_uri, const QImage &image); private slots: - void TempAlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResult result); + void TempAlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result); private: Application *app_; diff --git a/src/dialogs/edittagdialog.cpp b/src/dialogs/edittagdialog.cpp index d8aa94a62..755af5e8f 100644 --- a/src/dialogs/edittagdialog.cpp +++ b/src/dialogs/edittagdialog.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -341,7 +342,7 @@ bool EditTagDialog::eventFilter(QObject *o, QEvent *e) { if (event->mimeData()->hasImage()) { QImage image = qvariant_cast(event->mimeData()->imageData()); if (!image.isNull()) { - UpdateCover(UpdateCoverAction::New, AlbumCoverImageResult(image)); + UpdateCover(UpdateCoverAction::New, std::make_shared(image)); } } break; @@ -637,10 +638,10 @@ void EditTagDialog::SelectionChanged() { bool lyrics_enabled = false; for (const QModelIndex &idx : indexes) { if (data_[idx.row()].cover_action_ == UpdateCoverAction::None) { - data_[idx.row()].cover_result_ = AlbumCoverImageResult(); + data_[idx.row()].cover_result_ = std::make_shared(); } const Song &song = data_[idx.row()].original_; - if (data_[idx.row()].cover_action_ != first_cover_action || (first_cover_action != UpdateCoverAction::None && data_[idx.row()].cover_result_.image_data != data_[indexes.first().row()].cover_result_.image_data)) { + if (data_[idx.row()].cover_action_ != first_cover_action || (first_cover_action != UpdateCoverAction::None && data_[idx.row()].cover_result_->image_data != data_[indexes.first().row()].cover_result_->image_data)) { action_different = true; } if (data_[idx.row()].cover_action_ != first_cover_action || @@ -888,34 +889,34 @@ void EditTagDialog::UpdateStatisticsTab(const Song &song) { } -void EditTagDialog::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) { +void EditTagDialog::AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result) { if (id == tags_cover_art_id_) { ui_->tags_art->clear(); bool enable_change_art = false; - if (result.success && !result.image_scaled.isNull() && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset) { - ui_->tags_art->setPixmap(QPixmap::fromImage(result.image_scaled)); + if (result->success && !result->image_scaled.isNull() && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset) { + ui_->tags_art->setPixmap(QPixmap::fromImage(result->image_scaled)); for (const QModelIndex &idx : ui_->song_list->selectionModel()->selectedIndexes()) { - data_[idx.row()].cover_result_ = result.album_cover; + data_[idx.row()].cover_result_ = result->album_cover; enable_change_art = data_[idx.row()].original_.is_collection_song(); } } else { ui_->tags_art->setPixmap(QPixmap::fromImage(image_no_cover_thumbnail_)); for (const QModelIndex &idx : ui_->song_list->selectionModel()->selectedIndexes()) { - data_[idx.row()].cover_result_ = AlbumCoverImageResult(); + data_[idx.row()].cover_result_ = std::make_shared(); enable_change_art = data_[idx.row()].original_.is_collection_song(); } } tags_cover_art_id_ = -1; - album_cover_choice_controller_->show_cover_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset); - album_cover_choice_controller_->cover_to_file_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset); - album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && result.success && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset); + album_cover_choice_controller_->show_cover_action()->setEnabled(result->success && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset); + album_cover_choice_controller_->cover_to_file_action()->setEnabled(result->success && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset); + album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && result->success && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset); } else if (id == summary_cover_art_id_) { - if (result.success && !result.image_scaled.isNull() && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset) { - ui_->summary_art->setPixmap(QPixmap::fromImage(result.image_scaled)); + if (result->success && !result->image_scaled.isNull() && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset) { + ui_->summary_art->setPixmap(QPixmap::fromImage(result->image_scaled)); } else { ui_->summary_art->setPixmap(QPixmap::fromImage(image_no_cover_thumbnail_)); @@ -980,8 +981,8 @@ void EditTagDialog::LoadCoverFromFile() { Song *song = GetFirstSelected(); if (!song) return; - AlbumCoverImageResult result = album_cover_choice_controller_->LoadImageFromFile(song); - if (result.is_valid()) UpdateCover(UpdateCoverAction::New, result); + AlbumCoverImageResultPtr result = album_cover_choice_controller_->LoadImageFromFile(song); + if (result && result->is_valid()) UpdateCover(UpdateCoverAction::New, result); } @@ -998,8 +999,8 @@ void EditTagDialog::LoadCoverFromURL() { if (ui_->song_list->selectionModel()->selectedIndexes().isEmpty()) return; - AlbumCoverImageResult result = album_cover_choice_controller_->LoadImageFromURL(); - if (result.is_valid()) UpdateCover(UpdateCoverAction::New, result); + AlbumCoverImageResultPtr result = album_cover_choice_controller_->LoadImageFromURL(); + if (result && result->is_valid()) UpdateCover(UpdateCoverAction::New, result); } @@ -1008,8 +1009,8 @@ void EditTagDialog::SearchForCover() { Song *song = GetFirstSelected(); if (!song) return; - AlbumCoverImageResult result = album_cover_choice_controller_->SearchForImage(song); - if (result.is_valid()) UpdateCover(UpdateCoverAction::New, result); + AlbumCoverImageResultPtr result = album_cover_choice_controller_->SearchForImage(song); + if (result && result->is_valid()) UpdateCover(UpdateCoverAction::New, result); } @@ -1046,11 +1047,11 @@ void EditTagDialog::ShowCover() { if (ui_->song_list->selectionModel()->selectedIndexes().isEmpty()) return; const Data &first_data = data_[ui_->song_list->selectionModel()->selectedIndexes().first().row()]; - album_cover_choice_controller_->ShowCover(first_data.current_, first_data.cover_result_.image); + album_cover_choice_controller_->ShowCover(first_data.current_, first_data.cover_result_->image); } -void EditTagDialog::UpdateCover(const UpdateCoverAction action, const AlbumCoverImageResult &result) { +void EditTagDialog::UpdateCover(const UpdateCoverAction action, AlbumCoverImageResultPtr result) { const QModelIndexList indexes = ui_->song_list->selectionModel()->selectedIndexes(); if (indexes.isEmpty()) return; @@ -1165,8 +1166,8 @@ void EditTagDialog::SaveData() { if ((!ref.current_.effective_albumartist().isEmpty() && !ref.current_.album().isEmpty()) && (!ui_->checkbox_embedded_cover->isChecked() || !ref.original_.save_embedded_cover_supported())) { QUrl cover_url; - if (!ref.cover_result_.cover_url.isEmpty() && ref.cover_result_.cover_url.isLocalFile() && QFile::exists(ref.cover_result_.cover_url.toLocalFile())) { - cover_url = ref.cover_result_.cover_url; + if (!ref.cover_result_->cover_url.isEmpty() && ref.cover_result_->cover_url.isLocalFile() && QFile::exists(ref.cover_result_->cover_url.toLocalFile())) { + cover_url = ref.cover_result_->cover_url; } else { QString cover_hash = CoverUtils::Sha1CoverHash(ref.current_.effective_albumartist(), ref.current_.album()).toHex(); @@ -1223,9 +1224,9 @@ void EditTagDialog::SaveData() { TagReaderClient::SaveCoverOptions savecover_options; savecover_options.enabled = save_embedded_cover; if (save_embedded_cover && ref.cover_action_ == UpdateCoverAction::New) { - if (!ref.cover_result_.image.isNull()) { - savecover_options.is_jpeg = ref.cover_result_.is_jpeg(); - savecover_options.cover_data = ref.cover_result_.image_data; + if (!ref.cover_result_->image.isNull()) { + savecover_options.is_jpeg = ref.cover_result_->is_jpeg(); + savecover_options.cover_data = ref.cover_result_->image_data; } else if (!embedded_cover_from_file.isEmpty()) { savecover_options.cover_filename = embedded_cover_from_file; diff --git a/src/dialogs/edittagdialog.h b/src/dialogs/edittagdialog.h index 4d8f67c09..76187e346 100644 --- a/src/dialogs/edittagdialog.h +++ b/src/dialogs/edittagdialog.h @@ -93,7 +93,7 @@ class EditTagDialog : public QDialog { New }; struct Data { - explicit Data(const Song &song = Song()) : original_(song), current_(song), cover_action_(UpdateCoverAction::None) {} + explicit Data(const Song &song = Song()) : original_(song), current_(song), cover_action_(UpdateCoverAction::None), cover_result_(std::make_shared()) {} static QVariant value(const Song &song, const QString &id); QVariant original_value(const QString &id) const { return value(original_, id); } @@ -104,7 +104,7 @@ class EditTagDialog : public QDialog { Song original_; Song current_; UpdateCoverAction cover_action_; - AlbumCoverImageResult cover_result_; + AlbumCoverImageResultPtr cover_result_; }; private slots: @@ -120,7 +120,7 @@ class EditTagDialog : public QDialog { void FetchTag(); void FetchTagSongChosen(const Song &original_song, const Song &new_metadata); - void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result); + void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result); void LoadCoverFromFile(); void SaveCoverToFile(); @@ -147,7 +147,7 @@ class EditTagDialog : public QDialog { }; Song *GetFirstSelected(); - void UpdateCover(const UpdateCoverAction action, const AlbumCoverImageResult &result = AlbumCoverImageResult()); + void UpdateCover(const UpdateCoverAction action, AlbumCoverImageResultPtr result = AlbumCoverImageResultPtr()); bool DoesValueVary(const QModelIndexList &sel, const QString &id) const; bool IsValueModified(const QModelIndexList &sel, const QString &id) const; diff --git a/src/internet/internetsearchview.cpp b/src/internet/internetsearchview.cpp index dbaa997e7..48a7a0af6 100644 --- a/src/internet/internetsearchview.cpp +++ b/src/internet/internetsearchview.cpp @@ -857,7 +857,7 @@ void InternetSearchView::LazyLoadAlbumCover(const QModelIndex &proxy_index) { } -void InternetSearchView::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &albumcover_result) { +void InternetSearchView::AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr albumcover_result) { if (!cover_loader_tasks_.contains(id)) return; @@ -865,15 +865,15 @@ void InternetSearchView::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoad QModelIndex idx = cover_loader_task.first; QString key = cover_loader_task.second; - if (albumcover_result.success && !albumcover_result.image_scaled.isNull()) { - QPixmap pixmap = QPixmap::fromImage(albumcover_result.image_scaled); + if (albumcover_result && albumcover_result->success && !albumcover_result->image_scaled.isNull()) { + QPixmap pixmap = QPixmap::fromImage(albumcover_result->image_scaled); if (!pixmap.isNull()) { QPixmapCache::insert(key, pixmap); } if (idx.isValid()) { QStandardItem *item = front_model_->itemFromIndex(idx); if (item) { - item->setData(albumcover_result.image_scaled, Qt::DecorationRole); + item->setData(albumcover_result->image_scaled, Qt::DecorationRole); } } } diff --git a/src/internet/internetsearchview.h b/src/internet/internetsearchview.h index 95de3ecb3..c0fcf7bd5 100644 --- a/src/internet/internetsearchview.h +++ b/src/internet/internetsearchview.h @@ -173,7 +173,7 @@ class InternetSearchView : public QWidget { void GroupByClicked(QAction *action); void SetGroupBy(const CollectionModel::Grouping g); - void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &albumcover_result); + void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr albumcover_result); public slots: void ReloadSettings(); diff --git a/src/playlist/playlist.cpp b/src/playlist/playlist.cpp index 70015ae39..3967545ac 100644 --- a/src/playlist/playlist.cpp +++ b/src/playlist/playlist.cpp @@ -2316,14 +2316,16 @@ void Playlist::UpdateScrobblePoint(const qint64 seek_point_nanosec) { } -void Playlist::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result) { +void Playlist::AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result) { + + if (!result) return; // Update art_manual for local songs that are not in the collection. - if (((result.type == AlbumCoverLoaderResult::Type::Manual && result.album_cover.cover_url.isLocalFile()) || result.type == AlbumCoverLoaderResult::Type::ManuallyUnset) && (song.source() == Song::Source::LocalFile || song.source() == Song::Source::CDDA || song.source() == Song::Source::Device)) { + if (((result->type == AlbumCoverLoaderResult::Type::Manual && result->album_cover->cover_url.isLocalFile()) || result->type == AlbumCoverLoaderResult::Type::ManuallyUnset) && (song.source() == Song::Source::LocalFile || song.source() == Song::Source::CDDA || song.source() == Song::Source::Device)) { PlaylistItemPtr item = current_item(); - 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); + 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); ScheduleSaveAsync(); } } diff --git a/src/playlist/playlist.h b/src/playlist/playlist.h index 05bb92c49..fb47be3b9 100644 --- a/src/playlist/playlist.h +++ b/src/playlist/playlist.h @@ -320,7 +320,7 @@ class Playlist : public QAbstractListModel { void RepopulateDynamicPlaylist(); void TurnOffDynamicPlaylist(); - void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result); + void AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result); signals: void RestoreFinished(); diff --git a/src/playlist/playlistview.cpp b/src/playlist/playlistview.cpp index 83248a5d5..230dcd3ce 100644 --- a/src/playlist/playlistview.cpp +++ b/src/playlist/playlistview.cpp @@ -1467,11 +1467,11 @@ void PlaylistView::Stopped() { } -void PlaylistView::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result) { +void PlaylistView::AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result) { - if ((song != Song() && song_playing_ == Song()) || result.album_cover.image == current_song_cover_art_) return; + if (!result || (song != Song() && song_playing_ == Song()) || result->album_cover->image == current_song_cover_art_) return; - current_song_cover_art_ = result.album_cover.image; + current_song_cover_art_ = result->album_cover->image; if (background_image_type_ == AppearanceSettingsPage::BackgroundImageType::Album) { if (song.art_automatic().isEmpty() && song.art_manual().isEmpty()) { set_background_image(QImage()); diff --git a/src/playlist/playlistview.h b/src/playlist/playlistview.h index 6f756a3af..f0aebfc20 100644 --- a/src/playlist/playlistview.h +++ b/src/playlist/playlistview.h @@ -183,7 +183,7 @@ class PlaylistView : public QTreeView { void Playing(); void Stopped(); void SongChanged(const Song &song); - void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result = AlbumCoverLoaderResult()); + void AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result = AlbumCoverLoaderResultPtr()); void DynamicModeChanged(const bool dynamic); void SetRatingLockStatus(const bool state); void RatingHoverIn(const QModelIndex &idx, const QPoint pos); diff --git a/src/radios/radiomodel.cpp b/src/radios/radiomodel.cpp index fbc386733..e6c0b939f 100644 --- a/src/radios/radiomodel.cpp +++ b/src/radios/radiomodel.cpp @@ -307,7 +307,7 @@ QPixmap RadioModel::ChannelIcon(const QModelIndex &idx) { } -void RadioModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result) { +void RadioModel::AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result) { if (!pending_art_.contains(id)) return; @@ -319,11 +319,11 @@ void RadioModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult pending_cache_keys_.remove(cache_key); - if (!result.success || result.image_scaled.isNull() || result.type == AlbumCoverLoaderResult::Type::ManuallyUnset) { + if (!result || !result->success || result->image_scaled.isNull() || result->type == AlbumCoverLoaderResult::Type::ManuallyUnset) { QPixmapCache::insert(cache_key, ServiceIcon(item)); } else { - QPixmapCache::insert(cache_key, QPixmap::fromImage(result.image_scaled)); + QPixmapCache::insert(cache_key, QPixmap::fromImage(result->image_scaled)); } const QModelIndex idx = ItemToIndex(item); diff --git a/src/radios/radiomodel.h b/src/radios/radiomodel.h index 6cdb8e97a..cf8b5dd63 100644 --- a/src/radios/radiomodel.h +++ b/src/radios/radiomodel.h @@ -84,7 +84,7 @@ class RadioModel : public SimpleTreeModel { QString SortText(QString text); private slots: - void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result); + void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result); private: static const int kTreeIconSize;