Use std::shared_ptrfor AlbumCoverLoaderResult
Reduces memory fragmentation with Qt 6
This commit is contained in:
@@ -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;
|
if (!pending_art_.contains(id)) return;
|
||||||
|
|
||||||
@@ -667,19 +667,21 @@ void CollectionModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderR
|
|||||||
|
|
||||||
pending_cache_keys_.remove(cache_key);
|
pending_cache_keys_.remove(cache_key);
|
||||||
|
|
||||||
|
if (!result) return;
|
||||||
|
|
||||||
// Insert this image in the cache.
|
// 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.
|
// Set the no_cover image so we don't continually try to load art.
|
||||||
QPixmapCache::insert(cache_key, no_cover_icon_);
|
QPixmapCache::insert(cache_key, no_cover_icon_);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QPixmap image_pixmap;
|
QPixmap image_pixmap;
|
||||||
image_pixmap = QPixmap::fromImage(result.image_scaled);
|
image_pixmap = QPixmap::fromImage(result->image_scaled);
|
||||||
QPixmapCache::insert(cache_key, image_pixmap);
|
QPixmapCache::insert(cache_key, image_pixmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a valid cover not already in the disk cache
|
// 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<QIODevice> cached_img(sIconCache->data(QUrl(cache_key)));
|
std::unique_ptr<QIODevice> cached_img(sIconCache->data(QUrl(cache_key)));
|
||||||
if (!cached_img) {
|
if (!cached_img) {
|
||||||
QNetworkCacheMetaData item_metadata;
|
QNetworkCacheMetaData item_metadata;
|
||||||
@@ -687,7 +689,7 @@ void CollectionModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderR
|
|||||||
item_metadata.setUrl(QUrl(cache_key));
|
item_metadata.setUrl(QUrl(cache_key));
|
||||||
QIODevice *cache = sIconCache->prepare(item_metadata);
|
QIODevice *cache = sIconCache->prepare(item_metadata);
|
||||||
if (cache) {
|
if (cache) {
|
||||||
result.image_scaled.save(cache, "XPM");
|
result->image_scaled.save(cache, "XPM");
|
||||||
sIconCache->insert(cache);
|
sIconCache->insert(cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ class CollectionModel : public SimpleTreeModel<CollectionItem> {
|
|||||||
// Called after ResetAsync
|
// Called after ResetAsync
|
||||||
void ResetAsyncQueryFinished();
|
void ResetAsyncQueryFinished();
|
||||||
|
|
||||||
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
|
void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Provides some optimizations for loading the list of items in the root.
|
// Provides some optimizations for loading the list of items in the root.
|
||||||
|
|||||||
@@ -1296,7 +1296,7 @@ void MainWindow::MediaStopped() {
|
|||||||
|
|
||||||
song_playing_ = Song();
|
song_playing_ = Song();
|
||||||
song_ = Song();
|
song_ = Song();
|
||||||
album_cover_ = AlbumCoverImageResult();
|
album_cover_.reset();
|
||||||
|
|
||||||
app_->scrobbler()->ClearPlaying();
|
app_->scrobbler()->ClearPlaying();
|
||||||
|
|
||||||
@@ -3034,7 +3034,11 @@ void MainWindow::SearchForCover() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SaveCoverToFile() {
|
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() {
|
void MainWindow::UnsetCover() {
|
||||||
@@ -3050,7 +3054,11 @@ void MainWindow::DeleteCover() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::ShowCover() {
|
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() {
|
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;
|
if (song != song_playing_) return;
|
||||||
|
|
||||||
song_ = song;
|
song_ = song;
|
||||||
album_cover_ = result.album_cover;
|
if (result) {
|
||||||
|
album_cover_ = result->album_cover;
|
||||||
emit AlbumCoverReady(song, result.album_cover.image);
|
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();
|
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_->show_cover_action()->setEnabled(result && 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_->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_file_action()->setEnabled(enable_change_art);
|
||||||
album_cover_choice_controller_->cover_from_url_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_->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_->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_->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();
|
GetCoverAutomatically();
|
||||||
|
|
||||||
@@ -3085,13 +3098,12 @@ void MainWindow::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult
|
|||||||
void MainWindow::GetCoverAutomatically() {
|
void MainWindow::GetCoverAutomatically() {
|
||||||
|
|
||||||
// Search for cover automatically?
|
// Search for cover automatically?
|
||||||
bool search =
|
const bool search = album_cover_choice_controller_->search_cover_auto_action()->isChecked() &&
|
||||||
album_cover_choice_controller_->search_cover_auto_action()->isChecked() &&
|
!song_.has_manually_unset_cover() &&
|
||||||
!song_.has_manually_unset_cover() &&
|
!song_.art_automatic_is_valid() &&
|
||||||
!song_.art_automatic_is_valid() &&
|
!song_.art_manual_is_valid() &&
|
||||||
!song_.art_manual_is_valid() &&
|
!song_.effective_albumartist().isEmpty() &&
|
||||||
!song_.effective_albumartist().isEmpty() &&
|
!song_.effective_album().isEmpty();
|
||||||
!song_.effective_album().isEmpty();
|
|
||||||
|
|
||||||
if (search) {
|
if (search) {
|
||||||
emit SearchCoverInProgress();
|
emit SearchCoverInProgress();
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
|||||||
void DeleteCover();
|
void DeleteCover();
|
||||||
void ShowCover();
|
void ShowCover();
|
||||||
void SearchCoverAutomatically();
|
void SearchCoverAutomatically();
|
||||||
void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result);
|
void AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result);
|
||||||
|
|
||||||
void ScrobblingEnabledChanged(const bool value);
|
void ScrobblingEnabledChanged(const bool value);
|
||||||
void ScrobbleButtonVisibilityChanged(const bool value);
|
void ScrobbleButtonVisibilityChanged(const bool value);
|
||||||
@@ -391,7 +391,7 @@ class MainWindow : public QMainWindow, public PlatformInterface {
|
|||||||
|
|
||||||
Song song_;
|
Song song_;
|
||||||
Song song_playing_;
|
Song song_playing_;
|
||||||
AlbumCoverImageResult album_cover_;
|
AlbumCoverImageResultPtr album_cover_;
|
||||||
bool exit_;
|
bool exit_;
|
||||||
int exit_count_;
|
int exit_count_;
|
||||||
bool delete_files_;
|
bool delete_files_;
|
||||||
|
|||||||
@@ -123,6 +123,7 @@ void RegisterMetaTypes() {
|
|||||||
qRegisterMetaType<PlaylistSequence::RepeatMode>("PlaylistSequence::RepeatMode");
|
qRegisterMetaType<PlaylistSequence::RepeatMode>("PlaylistSequence::RepeatMode");
|
||||||
qRegisterMetaType<PlaylistSequence::ShuffleMode>("PlaylistSequence::ShuffleMode");
|
qRegisterMetaType<PlaylistSequence::ShuffleMode>("PlaylistSequence::ShuffleMode");
|
||||||
qRegisterMetaType<AlbumCoverLoaderResult>("AlbumCoverLoaderResult");
|
qRegisterMetaType<AlbumCoverLoaderResult>("AlbumCoverLoaderResult");
|
||||||
|
qRegisterMetaType<AlbumCoverLoaderResultPtr>("AlbumCoverLoaderResultPtr");
|
||||||
qRegisterMetaType<AlbumCoverLoaderResult::Type>("AlbumCoverLoaderResult::Type");
|
qRegisterMetaType<AlbumCoverLoaderResult::Type>("AlbumCoverLoaderResult::Type");
|
||||||
qRegisterMetaType<CoverProviderSearchResult>("CoverProviderSearchResult");
|
qRegisterMetaType<CoverProviderSearchResult>("CoverProviderSearchResult");
|
||||||
qRegisterMetaType<CoverProviderSearchResults>("CoverProviderSearchResults");
|
qRegisterMetaType<CoverProviderSearchResults>("CoverProviderSearchResults");
|
||||||
|
|||||||
@@ -386,7 +386,9 @@ void Mpris2::CurrentSongChanged(const Song &song) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ... and we add the cover information later, when it's available.
|
// ... 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();
|
last_metadata_ = QVariantMap();
|
||||||
song.ToXesam(&last_metadata_);
|
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_);
|
AddMetadata("mpris:trackid", current_track_id(), &last_metadata_);
|
||||||
|
|
||||||
QUrl cover_url;
|
QUrl cover_url;
|
||||||
if (result.album_cover.cover_url.isValid() && result.album_cover.cover_url.isLocalFile() && QFile(result.album_cover.cover_url.toLocalFile()).exists()) {
|
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;
|
cover_url = result->album_cover->cover_url;
|
||||||
}
|
}
|
||||||
else if (result.temp_cover_url.isValid() && result.temp_cover_url.isLocalFile()) {
|
else if (result->temp_cover_url.isValid() && result->temp_cover_url.isLocalFile()) {
|
||||||
cover_url = result.temp_cover_url;
|
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) {
|
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();
|
cover_url = song.art_manual();
|
||||||
|
|||||||
@@ -202,7 +202,7 @@ class Mpris2 : public QObject {
|
|||||||
void PlaylistChanged(MprisPlaylist playlist);
|
void PlaylistChanged(MprisPlaylist playlist);
|
||||||
|
|
||||||
private slots:
|
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 EngineStateChanged(Engine::State newState);
|
||||||
void VolumeChanged();
|
void VolumeChanged();
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
QStandardItem *item = pending_covers_.take(id);
|
||||||
if (!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
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(QIcon(QPixmap::fromImage(result.image_scaled)));
|
item->setIcon(QIcon(QPixmap::fromImage(result->image_scaled)));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class StandardItemIconLoader : public QObject {
|
|||||||
void LoadIcon(const Song &song, QStandardItem *for_item);
|
void LoadIcon(const Song &song, QStandardItem *for_item);
|
||||||
|
|
||||||
private slots:
|
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 RowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end);
|
||||||
void ModelReset();
|
void ModelReset();
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QtConcurrentRun>
|
#include <QtConcurrentRun>
|
||||||
@@ -168,27 +170,27 @@ QList<QAction*> 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));
|
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<AlbumCoverImageResult>();
|
||||||
QFile file(cover_file);
|
QFile file(cover_file);
|
||||||
if (file.open(QIODevice::ReadOnly)) {
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
result.image_data = file.readAll();
|
result->image_data = file.readAll();
|
||||||
file.close();
|
file.close();
|
||||||
if (result.image_data.isEmpty()) {
|
if (result->image_data.isEmpty()) {
|
||||||
qLog(Error) << "Cover file" << cover_file << "is empty.";
|
qLog(Error) << "Cover file" << cover_file << "is empty.";
|
||||||
emit Error(tr("Cover file %1 is empty.").arg(cover_file));
|
emit Error(tr("Cover file %1 is empty.").arg(cover_file));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result.mime_type = Utilities::MimeTypeFromData(result.image_data);
|
result->mime_type = Utilities::MimeTypeFromData(result->image_data);
|
||||||
result.image.loadFromData(result.image_data);
|
result->image.loadFromData(result->image_data);
|
||||||
result.cover_url = QUrl::fromLocalFile(cover_file);
|
result->cover_url = QUrl::fromLocalFile(cover_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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 = "/";
|
QString initial_file_name = "/";
|
||||||
|
|
||||||
@@ -256,10 +260,10 @@ void AlbumCoverChoiceController::SaveCoverToFileManual(const Song &song, const A
|
|||||||
fileinfo.setFile(save_filename);
|
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);
|
QFile file(save_filename);
|
||||||
if (file.open(QIODevice::WriteOnly)) {
|
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();
|
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()));
|
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 {
|
else {
|
||||||
if (!result.image.save(save_filename)) {
|
if (!result->image.save(save_filename)) {
|
||||||
qLog(Error) << "Failed writing cover to file" << save_filename;
|
qLog(Error) << "Failed writing cover to file" << save_filename;
|
||||||
emit Error(tr("Failed writing cover to file %1.").arg(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();
|
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();
|
return QUrl();
|
||||||
}
|
}
|
||||||
else {
|
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); }
|
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();
|
if (!song->url().isLocalFile() || song->effective_albumartist().isEmpty() || song->album().isEmpty()) return QUrl();
|
||||||
|
|
||||||
// Get something sensible to stick in the search box
|
// Get something sensible to stick in the search box
|
||||||
AlbumCoverImageResult result = SearchForImage(song);
|
AlbumCoverImageResultPtr result = SearchForImage(song);
|
||||||
if (result.is_valid()) {
|
if (result->is_valid()) {
|
||||||
return SaveCoverAutomatic(song, result);
|
return SaveCoverAutomatic(song, result);
|
||||||
}
|
}
|
||||||
else {
|
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();
|
QString album = song->effective_album();
|
||||||
album = album.remove(Song::kAlbumRemoveDisc).remove(Song::kAlbumRemoveMisc);
|
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->url().isLocalFile() || song->effective_albumartist().isEmpty() || song->album().isEmpty()) return false;
|
||||||
|
|
||||||
if (song->has_embedded_cover() && song->save_embedded_cover_supported()) {
|
if (song->has_embedded_cover() && song->save_embedded_cover_supported()) {
|
||||||
SaveCoverEmbeddedAutomatic(*song, AlbumCoverImageResult());
|
SaveCoverEmbeddedAutomatic(*song, std::make_shared<AlbumCoverImageResult>());
|
||||||
}
|
}
|
||||||
|
|
||||||
QString art_automatic;
|
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);
|
Q_UNUSED(statistics);
|
||||||
|
|
||||||
@@ -526,7 +530,7 @@ void AlbumCoverChoiceController::AlbumCoverFetched(const quint64 id, const Album
|
|||||||
song = cover_fetching_tasks_.take(id);
|
song = cover_fetching_tasks_.take(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.is_valid()) {
|
if (result && result->is_valid()) {
|
||||||
SaveCoverAutomatic(&song, result);
|
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(),
|
return SaveCoverToFileAutomatic(song->source(),
|
||||||
song->effective_albumartist(),
|
song->effective_albumartist(),
|
||||||
@@ -613,10 +617,12 @@ QUrl AlbumCoverChoiceController::SaveCoverToFileAutomatic(const Song::Source sou
|
|||||||
const QString &album,
|
const QString &album,
|
||||||
const QString &album_id,
|
const QString &album_id,
|
||||||
const QString &album_dir,
|
const QString &album_dir,
|
||||||
const AlbumCoverImageResult &result,
|
AlbumCoverImageResultPtr result,
|
||||||
const bool force_overwrite) {
|
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();
|
if (filepath.isEmpty()) return QUrl();
|
||||||
|
|
||||||
QFile file(filepath);
|
QFile file(filepath);
|
||||||
@@ -630,9 +636,9 @@ QUrl AlbumCoverChoiceController::SaveCoverToFileAutomatic(const Song::Source sou
|
|||||||
}
|
}
|
||||||
|
|
||||||
QUrl cover_url;
|
QUrl cover_url;
|
||||||
if (result.is_jpeg()) {
|
if (result->is_jpeg()) {
|
||||||
if (file.open(QIODevice::WriteOnly)) {
|
if (file.open(QIODevice::WriteOnly)) {
|
||||||
if (file.write(result.image_data) > 0) {
|
if (file.write(result->image_data) > 0) {
|
||||||
cover_url = QUrl::fromLocalFile(filepath);
|
cover_url = QUrl::fromLocalFile(filepath);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -647,14 +653,16 @@ QUrl AlbumCoverChoiceController::SaveCoverToFileAutomatic(const Song::Source sou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
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;
|
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 (song.source() == Song::Source::Collection) {
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||||
@@ -669,13 +677,13 @@ void AlbumCoverChoiceController::SaveCoverEmbeddedAutomatic(const Song &song, co
|
|||||||
QList<QUrl> urls;
|
QList<QUrl> urls;
|
||||||
urls.reserve(songs.count());
|
urls.reserve(songs.count());
|
||||||
for (const Song &s : songs) urls << s.url();
|
for (const Song &s : songs) urls << s.url();
|
||||||
if (result.is_jpeg()) {
|
if (result->is_jpeg()) {
|
||||||
quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image_data);
|
quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image_data);
|
||||||
QMutexLocker l(&mutex_cover_save_tasks_);
|
QMutexLocker l(&mutex_cover_save_tasks_);
|
||||||
cover_save_tasks_.insert(id, song);
|
cover_save_tasks_.insert(id, song);
|
||||||
}
|
}
|
||||||
else {
|
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_);
|
QMutexLocker l(&mutex_cover_save_tasks_);
|
||||||
cover_save_tasks_.insert(id, song);
|
cover_save_tasks_.insert(id, song);
|
||||||
}
|
}
|
||||||
@@ -683,11 +691,11 @@ void AlbumCoverChoiceController::SaveCoverEmbeddedAutomatic(const Song &song, co
|
|||||||
watcher->setFuture(future);
|
watcher->setFuture(future);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (result.is_jpeg()) {
|
if (result->is_jpeg()) {
|
||||||
app_->album_cover_loader()->SaveEmbeddedCoverAsync(song.url().toLocalFile(), result.image_data);
|
app_->album_cover_loader()->SaveEmbeddedCoverAsync(song.url().toLocalFile(), result->image_data);
|
||||||
}
|
}
|
||||||
else {
|
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()) {
|
if (e->mimeData()->hasImage()) {
|
||||||
QImage image = qvariant_cast<QImage>(e->mimeData()->imageData());
|
QImage image = qvariant_cast<QImage>(e->mimeData()->imageData());
|
||||||
if (!image.isNull()) {
|
if (!image.isNull()) {
|
||||||
return SaveCoverAutomatic(song, AlbumCoverImageResult(image));
|
return SaveCoverAutomatic(song, std::make_shared<AlbumCoverImageResult>(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;
|
QUrl cover_url;
|
||||||
switch(get_save_album_cover_type()) {
|
switch(get_save_album_cover_type()) {
|
||||||
|
|||||||
@@ -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.
|
// 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.
|
// Otherwise, the path to the chosen cover will be returned.
|
||||||
AlbumCoverImageResult LoadImageFromFile(Song *song);
|
AlbumCoverImageResultPtr LoadImageFromFile(Song *song);
|
||||||
QUrl LoadCoverFromFile(Song *song);
|
QUrl LoadCoverFromFile(Song *song);
|
||||||
|
|
||||||
// Shows a dialog that allows user to save the given image on disk.
|
// 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.
|
// 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.
|
// 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.
|
// This returns the downloaded image or null image if something went wrong for example when user cancelled the dialog.
|
||||||
QUrl LoadCoverFromURL(Song *song);
|
QUrl LoadCoverFromURL(Song *song);
|
||||||
AlbumCoverImageResult LoadImageFromURL();
|
AlbumCoverImageResultPtr LoadImageFromURL();
|
||||||
|
|
||||||
// Lets the user choose a cover among all that have been found on last.fm.
|
// 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.
|
// Returns the chosen cover or null cover if user didn't choose anything.
|
||||||
QUrl SearchForCover(Song *song);
|
QUrl SearchForCover(Song *song);
|
||||||
AlbumCoverImageResult SearchForImage(Song *song);
|
AlbumCoverImageResultPtr SearchForImage(Song *song);
|
||||||
|
|
||||||
// Returns a path which indicates that the cover has been unset manually.
|
// Returns a path which indicates that the cover has been unset manually.
|
||||||
QUrl UnsetCover(Song *song, const bool clear_art_automatic = false);
|
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);
|
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.
|
// 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 SaveCoverAutomatic(Song *song, AlbumCoverImageResultPtr result);
|
||||||
QUrl SaveCoverToFileAutomatic(const Song *song, const AlbumCoverImageResult &result, const bool force_overwrite = false);
|
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, 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, AlbumCoverImageResultPtr result, const bool force_overwrite = false);
|
||||||
void SaveCoverEmbeddedAutomatic(const Song &song, const AlbumCoverImageResult &result);
|
void SaveCoverEmbeddedAutomatic(const Song &song, AlbumCoverImageResultPtr result);
|
||||||
void SaveCoverEmbeddedAutomatic(const Song &song, const QUrl &cover_url);
|
void SaveCoverEmbeddedAutomatic(const Song &song, const QUrl &cover_url);
|
||||||
void SaveCoverEmbeddedAutomatic(const Song &song, const QString &cover_filename);
|
void SaveCoverEmbeddedAutomatic(const Song &song, const QString &cover_filename);
|
||||||
void SaveCoverEmbeddedAutomatic(const QList<QUrl> &urls, const QImage &image);
|
void SaveCoverEmbeddedAutomatic(const QList<QUrl> &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; }
|
void set_save_embedded_cover_override(const bool value) { save_embedded_cover_override_ = value; }
|
||||||
|
|
||||||
private slots:
|
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);
|
void SaveEmbeddedCoverAsyncFinished(quint64 id, const bool success, const bool cleared);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|||||||
@@ -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;
|
if (!active_requests_.contains(request_id)) return;
|
||||||
AlbumCoverFetcherSearch *search = active_requests_.take(request_id);
|
AlbumCoverFetcherSearch *search = active_requests_.take(request_id);
|
||||||
|
|||||||
@@ -118,12 +118,12 @@ class AlbumCoverFetcher : public QObject {
|
|||||||
void Clear();
|
void Clear();
|
||||||
|
|
||||||
signals:
|
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);
|
void SearchFinished(quint64 request_id, CoverProviderSearchResults results, CoverSearchStatistics statistics);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void SingleSearchFinished(const quint64, const CoverProviderSearchResults &results);
|
void SingleSearchFinished(const quint64, const CoverProviderSearchResults &results);
|
||||||
void SingleCoverFetched(const quint64, const AlbumCoverImageResult &result);
|
void SingleCoverFetched(const quint64, AlbumCoverImageResultPtr result);
|
||||||
void StartRequests();
|
void StartRequests();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
@@ -256,7 +257,7 @@ void AlbumCoverFetcherSearch::AllProvidersFinished() {
|
|||||||
// No results?
|
// No results?
|
||||||
if (results_.isEmpty()) {
|
if (results_.isEmpty()) {
|
||||||
statistics_.missing_images_++;
|
statistics_.missing_images_++;
|
||||||
emit AlbumCoverFetched(request_.id, AlbumCoverImageResult());
|
emit AlbumCoverFetched(request_.id, AlbumCoverImageResultPtr());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +333,7 @@ void AlbumCoverFetcherSearch::ProviderCoverFetchFinished(QNetworkReply *reply) {
|
|||||||
}
|
}
|
||||||
result.image_size = image.size();
|
result.image_size = image.size();
|
||||||
result.score_quality = ScoreImage(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<AlbumCoverImageResult>(result.image_url, mime_type, image_data, image)));
|
||||||
qLog(Debug) << reply->url() << "from" << result.provider << "scored" << result.score();
|
qLog(Debug) << reply->url() << "from" << result.provider << "scored" << result.score();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -380,7 +381,7 @@ float AlbumCoverFetcherSearch::ScoreImage(const QSize size) {
|
|||||||
|
|
||||||
void AlbumCoverFetcherSearch::SendBestImage() {
|
void AlbumCoverFetcherSearch::SendBestImage() {
|
||||||
|
|
||||||
AlbumCoverImageResult result;
|
AlbumCoverImageResultPtr result = std::make_shared<AlbumCoverImageResult>();
|
||||||
|
|
||||||
if (!candidate_images_.isEmpty()) {
|
if (!candidate_images_.isEmpty()) {
|
||||||
QList<CandidateImage> candidate_images = candidate_images_.values();
|
QList<CandidateImage> candidate_images = candidate_images_.values();
|
||||||
@@ -391,8 +392,8 @@ void AlbumCoverFetcherSearch::SendBestImage() {
|
|||||||
|
|
||||||
statistics_.chosen_images_by_provider_[best_image.result.provider]++;
|
statistics_.chosen_images_by_provider_[best_image.result.provider]++;
|
||||||
statistics_.chosen_images_++;
|
statistics_.chosen_images_++;
|
||||||
statistics_.chosen_width_ += result.image.width();
|
statistics_.chosen_width_ += result->image.width();
|
||||||
statistics_.chosen_height_ += result.image.height();
|
statistics_.chosen_height_ += result->image.height();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
statistics_.missing_images_++;
|
statistics_.missing_images_++;
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class AlbumCoverFetcherSearch : public QObject {
|
|||||||
void SearchFinished(quint64, CoverProviderSearchResults results);
|
void SearchFinished(quint64, CoverProviderSearchResults results);
|
||||||
|
|
||||||
// It's the end of search and we've fetched a cover.
|
// 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:
|
private slots:
|
||||||
void ProviderSearchResults(const int id, const CoverProviderSearchResults &results);
|
void ProviderSearchResults(const int id, const CoverProviderSearchResults &results);
|
||||||
@@ -108,9 +108,9 @@ class AlbumCoverFetcherSearch : public QObject {
|
|||||||
|
|
||||||
// QMap is sorted by key (score).
|
// QMap is sorted by key (score).
|
||||||
struct CandidateImage {
|
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;
|
CoverProviderSearchResult result;
|
||||||
AlbumCoverImageResult album_cover;
|
AlbumCoverImageResultPtr album_cover;
|
||||||
};
|
};
|
||||||
QMultiMap<float, CandidateImage> candidate_images_;
|
QMultiMap<float, CandidateImage> candidate_images_;
|
||||||
|
|
||||||
|
|||||||
@@ -22,21 +22,24 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QMetaType>
|
#include <QMetaType>
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
||||||
struct AlbumCoverImageResult {
|
class AlbumCoverImageResult {
|
||||||
|
public:
|
||||||
explicit AlbumCoverImageResult(const QUrl &_cover_url = QUrl(),
|
explicit AlbumCoverImageResult(const QUrl &_cover_url = QUrl(),
|
||||||
const QString &_mime_type = QString(),
|
const QString &_mime_type = QString(),
|
||||||
const QByteArray &_image_data = QByteArray(),
|
const QByteArray &_image_data = QByteArray(),
|
||||||
const QImage &_image = QImage()) :
|
const QImage &_image = QImage())
|
||||||
cover_url(_cover_url),
|
: cover_url(_cover_url),
|
||||||
mime_type(_mime_type),
|
mime_type(_mime_type),
|
||||||
image_data(_image_data), image(_image) {}
|
image_data(_image_data),
|
||||||
|
image(_image) {}
|
||||||
explicit AlbumCoverImageResult(const QImage &_image) : image(_image) {}
|
explicit AlbumCoverImageResult(const QImage &_image) : image(_image) {}
|
||||||
|
|
||||||
QUrl cover_url;
|
QUrl cover_url;
|
||||||
@@ -48,6 +51,10 @@ struct AlbumCoverImageResult {
|
|||||||
bool is_jpeg() const { return mime_type == "image/jpeg" && !image_data.isEmpty(); }
|
bool is_jpeg() const { return mime_type == "image/jpeg" && !image_data.isEmpty(); }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using AlbumCoverImageResultPtr = std::shared_ptr<AlbumCoverImageResult>;
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(AlbumCoverImageResult)
|
Q_DECLARE_METATYPE(AlbumCoverImageResult)
|
||||||
|
Q_DECLARE_METATYPE(AlbumCoverImageResultPtr)
|
||||||
|
|
||||||
#endif // ALBUMCOVERIMAGERESULT_H
|
#endif // ALBUMCOVERIMAGERESULT_H
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
@@ -81,8 +83,9 @@ void AlbumCoverLoader::Exit() {
|
|||||||
void AlbumCoverLoader::CancelTask(const quint64 id) {
|
void AlbumCoverLoader::CancelTask(const quint64 id) {
|
||||||
|
|
||||||
QMutexLocker l(&mutex_load_image_async_);
|
QMutexLocker l(&mutex_load_image_async_);
|
||||||
for (QQueue<Task>::iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
|
for (QQueue<TaskPtr>::iterator it = tasks_.begin(); it != tasks_.end(); ++it) {
|
||||||
if (it->id == id) {
|
TaskPtr task = *it;
|
||||||
|
if (task->id == id) {
|
||||||
tasks_.erase(it); // clazy:exclude=strict-iterators
|
tasks_.erase(it); // clazy:exclude=strict-iterators
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -93,8 +96,9 @@ void AlbumCoverLoader::CancelTask(const quint64 id) {
|
|||||||
void AlbumCoverLoader::CancelTasks(const QSet<quint64> &ids) {
|
void AlbumCoverLoader::CancelTasks(const QSet<quint64> &ids) {
|
||||||
|
|
||||||
QMutexLocker l(&mutex_load_image_async_);
|
QMutexLocker l(&mutex_load_image_async_);
|
||||||
for (QQueue<Task>::iterator it = tasks_.begin(); it != tasks_.end();) {
|
for (QQueue<TaskPtr>::iterator it = tasks_.begin(); it != tasks_.end();) {
|
||||||
if (ids.contains(it->id)) {
|
TaskPtr task = *it;
|
||||||
|
if (ids.contains(task->id)) {
|
||||||
it = tasks_.erase(it); // clazy:exclude=strict-iterators
|
it = tasks_.erase(it); // clazy:exclude=strict-iterators
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -106,10 +110,11 @@ void AlbumCoverLoader::CancelTasks(const QSet<quint64> &ids) {
|
|||||||
|
|
||||||
quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, const Song &song) {
|
quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, const Song &song) {
|
||||||
|
|
||||||
Task task;
|
TaskPtr task = std::make_shared<Task>();
|
||||||
task.options = options;
|
task->options = options;
|
||||||
task.song = song;
|
task->song = song;
|
||||||
task.state = State::Manual;
|
task->state = State::Manual;
|
||||||
|
task->album_cover = std::make_shared<AlbumCoverImageResult>();
|
||||||
|
|
||||||
return EnqueueTask(task);
|
return EnqueueTask(task);
|
||||||
|
|
||||||
@@ -122,20 +127,21 @@ quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options,
|
|||||||
song.set_art_automatic(art_automatic);
|
song.set_art_automatic(art_automatic);
|
||||||
song.set_art_manual(art_manual);
|
song.set_art_manual(art_manual);
|
||||||
|
|
||||||
Task task;
|
TaskPtr task = std::make_shared<Task>();
|
||||||
task.options = options;
|
task->options = options;
|
||||||
task.song = song;
|
task->song = song;
|
||||||
task.state = State::Manual;
|
task->state = State::Manual;
|
||||||
|
task->album_cover = std::make_shared<AlbumCoverImageResult>();
|
||||||
|
|
||||||
return EnqueueTask(task);
|
return EnqueueTask(task);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, const AlbumCoverImageResult &album_cover) {
|
quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, AlbumCoverImageResultPtr album_cover) {
|
||||||
|
|
||||||
Task task;
|
TaskPtr task = std::make_shared<Task>();
|
||||||
task.options = options;
|
task->options = options;
|
||||||
task.album_cover = album_cover;
|
task->album_cover = album_cover;
|
||||||
|
|
||||||
return EnqueueTask(task);
|
return EnqueueTask(task);
|
||||||
|
|
||||||
@@ -143,25 +149,26 @@ quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options,
|
|||||||
|
|
||||||
quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, const QImage &image) {
|
quint64 AlbumCoverLoader::LoadImageAsync(const AlbumCoverLoaderOptions &options, const QImage &image) {
|
||||||
|
|
||||||
Task task;
|
TaskPtr task = std::make_shared<Task>();
|
||||||
task.options = options;
|
task->options = options;
|
||||||
task.album_cover.image = image;
|
task->album_cover = std::make_shared<AlbumCoverImageResult>();
|
||||||
|
task->album_cover->image = image;
|
||||||
|
|
||||||
return EnqueueTask(task);
|
return EnqueueTask(task);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quint64 AlbumCoverLoader::EnqueueTask(Task &task) {
|
quint64 AlbumCoverLoader::EnqueueTask(TaskPtr task) {
|
||||||
|
|
||||||
{
|
{
|
||||||
QMutexLocker l(&mutex_load_image_async_);
|
QMutexLocker l(&mutex_load_image_async_);
|
||||||
task.id = load_image_async_id_++;
|
task->id = load_image_async_id_++;
|
||||||
tasks_.enqueue(task);
|
tasks_.enqueue(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, "ProcessTasks", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "ProcessTasks", Qt::QueuedConnection);
|
||||||
|
|
||||||
return task.id;
|
return task->id;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,19 +176,19 @@ void AlbumCoverLoader::ProcessTasks() {
|
|||||||
|
|
||||||
while (!stop_requested_) {
|
while (!stop_requested_) {
|
||||||
// Get the next task
|
// Get the next task
|
||||||
Task task;
|
TaskPtr task;
|
||||||
{
|
{
|
||||||
QMutexLocker l(&mutex_load_image_async_);
|
QMutexLocker l(&mutex_load_image_async_);
|
||||||
if (tasks_.isEmpty()) return;
|
if (tasks_.isEmpty()) return;
|
||||||
task = tasks_.dequeue();
|
task = tasks_.dequeue();
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessTask(&task);
|
ProcessTask(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlbumCoverLoader::ProcessTask(Task *task) {
|
void AlbumCoverLoader::ProcessTask(TaskPtr task) {
|
||||||
|
|
||||||
TryLoadResult result = TryLoadImage(task);
|
TryLoadResult result = TryLoadImage(task);
|
||||||
if (result.started_async) {
|
if (result.started_async) {
|
||||||
@@ -190,16 +197,16 @@ void AlbumCoverLoader::ProcessTask(Task *task) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (result.loaded_success) {
|
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_scaled;
|
||||||
QImage image_thumbnail;
|
QImage image_thumbnail;
|
||||||
if (task->options.get_image_ && task->options.scale_output_image_) {
|
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_) {
|
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<AlbumCoverLoaderResult>(result.loaded_success, result.type, result.album_cover, image_scaled, image_thumbnail, task->art_updated));
|
||||||
return;
|
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) {
|
if (task->state == State::Manual) {
|
||||||
// Try the automatic one next
|
// Try the automatic one next
|
||||||
@@ -216,15 +223,15 @@ void AlbumCoverLoader::NextState(Task *task) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Give up
|
// 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<AlbumCoverLoaderResult>(false, AlbumCoverLoaderResult::Type::None, std::make_shared<AlbumCoverImageResult>(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.
|
// 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);
|
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.isEmpty() && !cover_url.path().isEmpty()) {
|
||||||
if (cover_url.path() == Song::kManuallyUnsetCover) {
|
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<AlbumCoverImageResult>(cover_url, QString(), QByteArray(), task->options.default_output_image_));
|
||||||
}
|
}
|
||||||
else if (cover_url.path() == Song::kEmbeddedCover && task->song.url().isLocalFile()) {
|
else if (cover_url.path() == Song::kEmbeddedCover && task->song.url().isLocalFile()) {
|
||||||
QByteArray image_data = TagReaderClient::Instance()->LoadEmbeddedArtBlocking(task->song.url().toLocalFile());
|
QByteArray image_data = TagReaderClient::Instance()->LoadEmbeddedArtBlocking(task->song.url().toLocalFile());
|
||||||
if (!image_data.isEmpty()) {
|
if (!image_data.isEmpty()) {
|
||||||
QImage image;
|
QImage image;
|
||||||
if (!image_data.isEmpty() && task->options.get_image_ && image.loadFromData(image_data)) {
|
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<AlbumCoverImageResult>(cover_url, QString(), image_data, image));
|
||||||
}
|
}
|
||||||
else {
|
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<AlbumCoverImageResult>(cover_url, QString(), image_data, image));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,10 +293,10 @@ AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(Task *task) {
|
|||||||
file.close();
|
file.close();
|
||||||
QImage image;
|
QImage image;
|
||||||
if (!image_data.isEmpty() && task->options.get_image_ && image.loadFromData(image_data)) {
|
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<AlbumCoverImageResult>(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image));
|
||||||
}
|
}
|
||||||
else {
|
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<AlbumCoverImageResult>(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -308,10 +315,10 @@ AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(Task *task) {
|
|||||||
file.close();
|
file.close();
|
||||||
QImage image;
|
QImage image;
|
||||||
if (!image_data.isEmpty() && task->options.get_image_ && image.loadFromData(image_data)) {
|
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<AlbumCoverImageResult>(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image));
|
||||||
}
|
}
|
||||||
else {
|
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<AlbumCoverImageResult>(cover_url, QString(), image_data, image.isNull() ? task->options.default_output_image_ : image));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -329,12 +336,12 @@ AlbumCoverLoader::TryLoadResult AlbumCoverLoader::TryLoadImage(Task *task) {
|
|||||||
QNetworkReply *reply = network_->get(request);
|
QNetworkReply *reply = network_->get(request);
|
||||||
QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, cover_url]() { RemoteFetchFinished(reply, cover_url); });
|
QObject::connect(reply, &QNetworkReply::finished, this, [this, reply, cover_url]() { RemoteFetchFinished(reply, cover_url); });
|
||||||
|
|
||||||
remote_tasks_.insert(reply, *task);
|
remote_tasks_.insert(reply, task);
|
||||||
return TryLoadResult(true, false, type, AlbumCoverImageResult(cover_url));
|
return TryLoadResult(true, false, type, std::make_shared<AlbumCoverImageResult>(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<AlbumCoverImageResult>(cover_url, QString(), QByteArray(), task->options.default_output_image_));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,12 +350,12 @@ void AlbumCoverLoader::RemoteFetchFinished(QNetworkReply *reply, const QUrl &cov
|
|||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|
||||||
if (!remote_tasks_.contains(reply)) return;
|
if (!remote_tasks_.contains(reply)) return;
|
||||||
Task task = remote_tasks_.take(reply);
|
TaskPtr task = remote_tasks_.take(reply);
|
||||||
|
|
||||||
// Handle redirects.
|
// Handle redirects.
|
||||||
QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
QVariant redirect = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||||
if (redirect.isValid()) {
|
if (redirect.isValid()) {
|
||||||
if (++task.redirects > kMaxRedirects) {
|
if (++task->redirects > kMaxRedirects) {
|
||||||
return; // Give up.
|
return; // Give up.
|
||||||
}
|
}
|
||||||
QNetworkRequest request = reply->request();
|
QNetworkRequest request = reply->request();
|
||||||
@@ -369,9 +376,9 @@ void AlbumCoverLoader::RemoteFetchFinished(QNetworkReply *reply, const QUrl &cov
|
|||||||
if (image.loadFromData(image_data)) {
|
if (image.loadFromData(image_data)) {
|
||||||
QImage image_scaled;
|
QImage image_scaled;
|
||||||
QImage image_thumbnail;
|
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.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_);
|
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));
|
emit AlbumCoverLoaded(task->id, std::make_shared<AlbumCoverLoaderResult>(true, task->type, std::make_shared<AlbumCoverImageResult>(cover_url, mime_type, (task->options.get_image_data_ ? image_data : QByteArray()), image), image_scaled, image_thumbnail, task->art_updated));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
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();
|
qLog(Error) << "Unable to get album cover" << cover_url << reply->error() << reply->errorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
NextState(&task);
|
NextState(task);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class AlbumCoverLoader : public QObject {
|
|||||||
|
|
||||||
quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const Song &song);
|
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 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);
|
quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const QImage &image);
|
||||||
|
|
||||||
void CancelTask(const quint64 id);
|
void CancelTask(const quint64 id);
|
||||||
@@ -79,7 +79,7 @@ class AlbumCoverLoader : public QObject {
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void ExitFinished();
|
void ExitFinished();
|
||||||
void AlbumCoverLoaded(quint64 id, AlbumCoverLoaderResult result);
|
void AlbumCoverLoaded(quint64 id, AlbumCoverLoaderResultPtr result);
|
||||||
void SaveEmbeddedCoverAsyncFinished(quint64 id, bool success, bool cleared);
|
void SaveEmbeddedCoverAsyncFinished(quint64 id, bool success, bool cleared);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
@@ -105,18 +105,19 @@ class AlbumCoverLoader : public QObject {
|
|||||||
|
|
||||||
quint64 id;
|
quint64 id;
|
||||||
Song song;
|
Song song;
|
||||||
AlbumCoverImageResult album_cover;
|
AlbumCoverImageResultPtr album_cover;
|
||||||
State state;
|
State state;
|
||||||
AlbumCoverLoaderResult::Type type;
|
AlbumCoverLoaderResult::Type type;
|
||||||
bool art_updated;
|
bool art_updated;
|
||||||
int redirects;
|
int redirects;
|
||||||
};
|
};
|
||||||
|
using TaskPtr = std::shared_ptr<Task>;
|
||||||
|
|
||||||
struct TryLoadResult {
|
struct TryLoadResult {
|
||||||
explicit TryLoadResult(const bool _started_async = false,
|
explicit TryLoadResult(const bool _started_async = false,
|
||||||
const bool _loaded_success = false,
|
const bool _loaded_success = false,
|
||||||
const AlbumCoverLoaderResult::Type _type = AlbumCoverLoaderResult::Type::None,
|
const AlbumCoverLoaderResult::Type _type = AlbumCoverLoaderResult::Type::None,
|
||||||
const AlbumCoverImageResult &_album_cover = AlbumCoverImageResult()) :
|
AlbumCoverImageResultPtr _album_cover = AlbumCoverImageResultPtr()) :
|
||||||
started_async(_started_async),
|
started_async(_started_async),
|
||||||
loaded_success(_loaded_success),
|
loaded_success(_loaded_success),
|
||||||
type(_type),
|
type(_type),
|
||||||
@@ -126,20 +127,20 @@ class AlbumCoverLoader : public QObject {
|
|||||||
bool loaded_success;
|
bool loaded_success;
|
||||||
|
|
||||||
AlbumCoverLoaderResult::Type type;
|
AlbumCoverLoaderResult::Type type;
|
||||||
AlbumCoverImageResult album_cover;
|
AlbumCoverImageResultPtr album_cover;
|
||||||
};
|
};
|
||||||
|
|
||||||
quint64 EnqueueTask(Task &task);
|
quint64 EnqueueTask(TaskPtr task);
|
||||||
void ProcessTask(Task *task);
|
void ProcessTask(TaskPtr task);
|
||||||
void NextState(Task *task);
|
void NextState(TaskPtr task);
|
||||||
TryLoadResult TryLoadImage(Task *task);
|
TryLoadResult TryLoadImage(TaskPtr task);
|
||||||
|
|
||||||
bool stop_requested_;
|
bool stop_requested_;
|
||||||
|
|
||||||
QMutex mutex_load_image_async_;
|
QMutex mutex_load_image_async_;
|
||||||
QMutex mutex_save_image_async_;
|
QMutex mutex_save_image_async_;
|
||||||
QQueue<Task> tasks_;
|
QQueue<TaskPtr> tasks_;
|
||||||
QHash<QNetworkReply*, Task> remote_tasks_;
|
QHash<QNetworkReply*, TaskPtr> remote_tasks_;
|
||||||
quint64 load_image_async_id_;
|
quint64 load_image_async_id_;
|
||||||
quint64 save_image_async_id_;
|
quint64 save_image_async_id_;
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
|
|
||||||
struct AlbumCoverLoaderOptions {
|
class AlbumCoverLoaderOptions {
|
||||||
|
public:
|
||||||
explicit AlbumCoverLoaderOptions()
|
explicit AlbumCoverLoaderOptions()
|
||||||
: get_image_data_(true),
|
: get_image_data_(true),
|
||||||
get_image_(true),
|
get_image_(true),
|
||||||
|
|||||||
@@ -22,12 +22,15 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
|
||||||
#include "albumcoverimageresult.h"
|
#include "albumcoverimageresult.h"
|
||||||
|
|
||||||
struct AlbumCoverLoaderResult {
|
class AlbumCoverLoaderResult {
|
||||||
|
public:
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
None,
|
None,
|
||||||
@@ -40,7 +43,7 @@ struct AlbumCoverLoaderResult {
|
|||||||
|
|
||||||
explicit AlbumCoverLoaderResult(const bool _success = false,
|
explicit AlbumCoverLoaderResult(const bool _success = false,
|
||||||
const Type _type = Type::None,
|
const Type _type = Type::None,
|
||||||
const AlbumCoverImageResult &_album_cover = AlbumCoverImageResult(),
|
AlbumCoverImageResultPtr _album_cover = AlbumCoverImageResultPtr(),
|
||||||
const QImage &_image_scaled = QImage(),
|
const QImage &_image_scaled = QImage(),
|
||||||
const QImage &_image_thumbnail = QImage(),
|
const QImage &_image_thumbnail = QImage(),
|
||||||
const bool _updated = false) :
|
const bool _updated = false) :
|
||||||
@@ -49,11 +52,17 @@ struct AlbumCoverLoaderResult {
|
|||||||
album_cover(_album_cover),
|
album_cover(_album_cover),
|
||||||
image_scaled(_image_scaled),
|
image_scaled(_image_scaled),
|
||||||
image_thumbnail(_image_thumbnail),
|
image_thumbnail(_image_thumbnail),
|
||||||
updated(_updated) {}
|
updated(_updated) {
|
||||||
|
|
||||||
|
if (!_album_cover) {
|
||||||
|
_album_cover = std::make_shared<AlbumCoverImageResult>();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool success;
|
bool success;
|
||||||
Type type;
|
Type type;
|
||||||
AlbumCoverImageResult album_cover;
|
AlbumCoverImageResultPtr album_cover;
|
||||||
QImage image_scaled;
|
QImage image_scaled;
|
||||||
QImage image_thumbnail;
|
QImage image_thumbnail;
|
||||||
bool updated;
|
bool updated;
|
||||||
@@ -62,4 +71,9 @@ struct AlbumCoverLoaderResult {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using AlbumCoverLoaderResultPtr = std::shared_ptr<AlbumCoverLoaderResult>;
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(AlbumCoverLoaderResult)
|
||||||
|
Q_DECLARE_METATYPE(AlbumCoverLoaderResultPtr)
|
||||||
|
|
||||||
#endif // ALBUMCOVERLOADERRESULT_H
|
#endif // ALBUMCOVERLOADERRESULT_H
|
||||||
|
|||||||
@@ -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;
|
if (!cover_loading_tasks_.contains(id)) return;
|
||||||
|
|
||||||
AlbumItem *item = cover_loading_tasks_.take(id);
|
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_);
|
item->setIcon(icon_nocover_item_);
|
||||||
}
|
}
|
||||||
else {
|
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_Image, result->image_original);
|
||||||
//item->setData(Role_ImageData, result.image_data);
|
//item->setData(Role_ImageData, result->image_data);
|
||||||
|
|
||||||
UpdateFilter();
|
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;
|
if (!cover_fetching_tasks_.contains(id)) return;
|
||||||
|
|
||||||
AlbumItem *item = cover_fetching_tasks_.take(id);
|
AlbumItem *item = cover_fetching_tasks_.take(id);
|
||||||
if (!result.image.isNull()) {
|
if (result && !result->image.isNull()) {
|
||||||
SaveAndSetCover(item, result);
|
SaveAndSetCover(item, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,8 +709,8 @@ void AlbumCoverManager::LoadCoverFromFile() {
|
|||||||
Song song = GetSingleSelectionAsSong();
|
Song song = GetSingleSelectionAsSong();
|
||||||
if (!song.is_valid()) return;
|
if (!song.is_valid()) return;
|
||||||
|
|
||||||
AlbumCoverImageResult result = album_cover_choice_controller_->LoadImageFromFile(&song);
|
AlbumCoverImageResultPtr result = album_cover_choice_controller_->LoadImageFromFile(&song);
|
||||||
if (!result.image.isNull()) {
|
if (result || !result->image.isNull()) {
|
||||||
SaveImageToAlbums(&song, result);
|
SaveImageToAlbums(&song, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -721,32 +721,32 @@ void AlbumCoverManager::SaveCoverToFile() {
|
|||||||
Song song = GetSingleSelectionAsSong();
|
Song song = GetSingleSelectionAsSong();
|
||||||
if (!song.is_valid() || song.has_manually_unset_cover()) return;
|
if (!song.is_valid() || song.has_manually_unset_cover()) return;
|
||||||
|
|
||||||
AlbumCoverImageResult result;
|
AlbumCoverImageResultPtr result = std::make_shared<AlbumCoverImageResult>();
|
||||||
|
|
||||||
// Load the image from disk
|
// 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())) {
|
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())) {
|
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()) {
|
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())) {
|
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())) {
|
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()) {
|
if (!result->image_data.isEmpty()) {
|
||||||
result.image.loadFromData(result.image_data);
|
result->image.loadFromData(result->image_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
album_cover_choice_controller_->SaveCoverToFileManual(song, result);
|
album_cover_choice_controller_->SaveCoverToFileManual(song, result);
|
||||||
@@ -758,8 +758,8 @@ void AlbumCoverManager::LoadCoverFromURL() {
|
|||||||
Song song = GetSingleSelectionAsSong();
|
Song song = GetSingleSelectionAsSong();
|
||||||
if (!song.is_valid()) return;
|
if (!song.is_valid()) return;
|
||||||
|
|
||||||
AlbumCoverImageResult result = album_cover_choice_controller_->LoadImageFromURL();
|
AlbumCoverImageResultPtr result = album_cover_choice_controller_->LoadImageFromURL();
|
||||||
if (result.is_valid()) {
|
if (result && result->is_valid()) {
|
||||||
SaveImageToAlbums(&song, result);
|
SaveImageToAlbums(&song, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,16 +770,18 @@ void AlbumCoverManager::SearchForCover() {
|
|||||||
Song song = GetFirstSelectedAsSong();
|
Song song = GetFirstSelectedAsSong();
|
||||||
if (!song.is_valid()) return;
|
if (!song.is_valid()) return;
|
||||||
|
|
||||||
AlbumCoverImageResult result = album_cover_choice_controller_->SearchForImage(&song);
|
AlbumCoverImageResultPtr result = album_cover_choice_controller_->SearchForImage(&song);
|
||||||
if (result.is_valid()) {
|
if (result && result->is_valid()) {
|
||||||
SaveImageToAlbums(&song, result);
|
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()) {
|
switch (album_cover_choice_controller_->get_save_album_cover_type()) {
|
||||||
case CoverOptions::CoverType::Cache:
|
case CoverOptions::CoverType::Cache:
|
||||||
case CoverOptions::CoverType::Album:
|
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()) {
|
if (album_cover_choice_controller_->get_save_album_cover_type() == CoverOptions::CoverType::Embedded && !urls.isEmpty()) {
|
||||||
quint64 id = -1;
|
quint64 id = -1;
|
||||||
if (result.is_jpeg()) {
|
if (result->is_jpeg()) {
|
||||||
id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image_data);
|
id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image_data);
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
for (AlbumItem *album_item : album_items) {
|
||||||
cover_save_tasks_.insert(id, album_item);
|
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 albumartist = item->data(Role_AlbumArtist).toString();
|
||||||
const QString album = item->data(Role_Album).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();
|
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 (album_cover_choice_controller_->get_save_album_cover_type() == CoverOptions::CoverType::Embedded && Song::save_embedded_cover_supported(filetype) && !has_cue) {
|
||||||
if (result.is_jpeg()) {
|
if (result->is_jpeg()) {
|
||||||
quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image_data);
|
quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image_data);
|
||||||
cover_save_tasks_.insert(id, item);
|
cover_save_tasks_.insert(id, item);
|
||||||
}
|
}
|
||||||
else if (!result.image.isNull()) {
|
else if (!result->image.isNull()) {
|
||||||
quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.image);
|
quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->image);
|
||||||
cover_save_tasks_.insert(id, item);
|
cover_save_tasks_.insert(id, item);
|
||||||
}
|
}
|
||||||
else if (!result.cover_url.isEmpty() && result.cover_url.isLocalFile()) {
|
else if (!result->cover_url.isEmpty() && result->cover_url.isLocalFile()) {
|
||||||
quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result.cover_url.toLocalFile());
|
quint64 id = app_->album_cover_loader()->SaveEmbeddedCoverAsync(urls, result->cover_url.toLocalFile());
|
||||||
cover_save_tasks_.insert(id, item);
|
cover_save_tasks_.insert(id, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QUrl cover_url;
|
QUrl cover_url;
|
||||||
if (!result.cover_url.isEmpty() && result.cover_url.isValid() && result.cover_url.isLocalFile()) {
|
if (!result->cover_url.isEmpty() && result->cover_url.isValid() && result->cover_url.isLocalFile()) {
|
||||||
cover_url = result.cover_url;
|
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);
|
cover_url = album_cover_choice_controller_->SaveCoverToFileAutomatic(Song::Source::Collection, albumartist, album, QString(), urls.first().adjusted(QUrl::RemoveFilename).path(), result, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,9 +137,9 @@ class AlbumCoverManager : public QMainWindow {
|
|||||||
|
|
||||||
void UpdateStatusText();
|
void UpdateStatusText();
|
||||||
bool ShouldHide(const AlbumItem &item, const QString &filter, const HideCovers hide_covers) const;
|
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;
|
SongList GetSongsInAlbums(const QModelIndexList &indexes) const;
|
||||||
SongMimeData *GetMimeDataForAlbums(const QModelIndexList &indexes) const;
|
SongMimeData *GetMimeDataForAlbums(const QModelIndexList &indexes) const;
|
||||||
@@ -152,11 +152,11 @@ class AlbumCoverManager : public QMainWindow {
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void ArtistChanged(QListWidgetItem *current);
|
void ArtistChanged(QListWidgetItem *current);
|
||||||
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
|
void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result);
|
||||||
void UpdateFilter();
|
void UpdateFilter();
|
||||||
void FetchAlbumCovers();
|
void FetchAlbumCovers();
|
||||||
void ExportCovers();
|
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();
|
void CancelRequests();
|
||||||
|
|
||||||
// On the context menu
|
// On the context menu
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
@@ -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_->artist->setText(artist);
|
||||||
ui_->album->setText(album);
|
ui_->album->setText(album);
|
||||||
@@ -171,16 +173,16 @@ AlbumCoverImageResult AlbumCoverSearcher::Exec(const QString &artist, const QStr
|
|||||||
Search();
|
Search();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exec() == QDialog::Rejected) return AlbumCoverImageResult();
|
if (exec() == QDialog::Rejected) return AlbumCoverImageResultPtr();
|
||||||
|
|
||||||
QModelIndex selected = ui_->covers->currentIndex();
|
QModelIndex selected = ui_->covers->currentIndex();
|
||||||
if (!selected.isValid() || !selected.data(Role_ImageFetchFinished).toBool())
|
if (!selected.isValid() || !selected.data(Role_ImageFetchFinished).toBool())
|
||||||
return AlbumCoverImageResult();
|
return AlbumCoverImageResultPtr();
|
||||||
|
|
||||||
AlbumCoverImageResult result;
|
AlbumCoverImageResultPtr result = std::make_shared<AlbumCoverImageResult>();
|
||||||
result.image_data = selected.data(Role_ImageData).toByteArray();
|
result->image_data = selected.data(Role_ImageData).toByteArray();
|
||||||
result.image = selected.data(Role_Image).value<QImage>();
|
result->image = selected.data(Role_Image).value<QImage>();
|
||||||
result.mime_type = Utilities::MimeTypeFromData(result.image_data);
|
result->mime_type = Utilities::MimeTypeFromData(result->image_data);
|
||||||
|
|
||||||
return result;
|
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;
|
if (!cover_loading_tasks_.contains(id)) return;
|
||||||
QStandardItem *item = cover_loading_tasks_.take(id);
|
QStandardItem *item = cover_loading_tasks_.take(id);
|
||||||
|
|
||||||
if (cover_loading_tasks_.isEmpty()) ui_->busy->hide();
|
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());
|
model_->removeRow(item->row());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap pixmap = QPixmap::fromImage(result.image_thumbnail);
|
const QPixmap pixmap = QPixmap::fromImage(result->image_thumbnail);
|
||||||
if (pixmap.isNull()) {
|
if (pixmap.isNull()) {
|
||||||
model_->removeRow(item->row());
|
model_->removeRow(item->row());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QIcon icon(pixmap);
|
const QIcon icon(pixmap);
|
||||||
|
|
||||||
item->setData(true, Role_ImageFetchFinished);
|
item->setData(true, Role_ImageFetchFinished);
|
||||||
item->setData(result.album_cover.image_data, Role_ImageData);
|
item->setData(result->album_cover->image_data, Role_ImageData);
|
||||||
item->setData(result.album_cover.image, Role_Image);
|
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.width() * result->album_cover->image.height(), Role_ImageDimensions);
|
||||||
item->setData(result.album_cover.image.size(), Role_ImageSize);
|
item->setData(result->album_cover->image.size(), Role_ImageSize);
|
||||||
if (!icon.isNull()) item->setIcon(icon);
|
if (!icon.isNull()) item->setIcon(icon);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,12 +83,12 @@ class AlbumCoverSearcher : public QDialog {
|
|||||||
Role_ImageData,
|
Role_ImageData,
|
||||||
Role_Image,
|
Role_Image,
|
||||||
Role_ImageDimensions,
|
Role_ImageDimensions,
|
||||||
Role_ImageSize,
|
Role_ImageSize
|
||||||
};
|
};
|
||||||
|
|
||||||
void Init(AlbumCoverFetcher *fetcher);
|
void Init(AlbumCoverFetcher *fetcher);
|
||||||
|
|
||||||
AlbumCoverImageResult Exec(const QString &artist, const QString &album);
|
AlbumCoverImageResultPtr Exec(const QString &artist, const QString &album);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void keyPressEvent(QKeyEvent*) override;
|
void keyPressEvent(QKeyEvent*) override;
|
||||||
@@ -96,7 +96,7 @@ class AlbumCoverSearcher : public QDialog {
|
|||||||
private slots:
|
private slots:
|
||||||
void Search();
|
void Search();
|
||||||
void SearchFinished(const quint64 id, const CoverProviderSearchResults &results);
|
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);
|
void CoverDoubleClicked(const QModelIndex &idx);
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
@@ -49,11 +51,11 @@ CoverFromURLDialog::~CoverFromURLDialog() {
|
|||||||
delete ui_;
|
delete ui_;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlbumCoverImageResult CoverFromURLDialog::Exec() {
|
AlbumCoverImageResultPtr CoverFromURLDialog::Exec() {
|
||||||
|
|
||||||
// reset state
|
// reset state
|
||||||
ui_->url->setText("");
|
ui_->url->setText("");
|
||||||
last_album_cover_ = AlbumCoverImageResult();
|
last_album_cover_.reset();
|
||||||
|
|
||||||
QClipboard *clipboard = QApplication::clipboard();
|
QClipboard *clipboard = QApplication::clipboard();
|
||||||
ui_->url->setText(clipboard->text());
|
ui_->url->setText(clipboard->text());
|
||||||
@@ -87,12 +89,12 @@ void CoverFromURLDialog::LoadCoverFromURLFinished() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AlbumCoverImageResult result;
|
AlbumCoverImageResultPtr result = std::make_shared<AlbumCoverImageResult>();
|
||||||
result.image_data = reply->readAll();
|
result->image_data = reply->readAll();
|
||||||
result.image.loadFromData(result.image_data);
|
result->image.loadFromData(result->image_data);
|
||||||
result.mime_type = Utilities::MimeTypeFromData(result.image_data);
|
result->mime_type = Utilities::MimeTypeFromData(result->image_data);
|
||||||
|
|
||||||
if (!result.image.isNull()) {
|
if (!result->image.isNull()) {
|
||||||
last_album_cover_ = result;
|
last_album_cover_ = result;
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class CoverFromURLDialog : public QDialog {
|
|||||||
~CoverFromURLDialog() override;
|
~CoverFromURLDialog() override;
|
||||||
|
|
||||||
// Opens the dialog. This returns an image found at the URL chosen by user or null image if the dialog got rejected.
|
// 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:
|
private slots:
|
||||||
void accept() override;
|
void accept() override;
|
||||||
@@ -54,7 +54,7 @@ class CoverFromURLDialog : public QDialog {
|
|||||||
Ui_CoverFromURLDialog *ui_;
|
Ui_CoverFromURLDialog *ui_;
|
||||||
|
|
||||||
NetworkAccessManager *network_;
|
NetworkAccessManager *network_;
|
||||||
AlbumCoverImageResult last_album_cover_;
|
AlbumCoverImageResultPtr last_album_cover_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COVERFROMURLDIALOG_H
|
#endif // COVERFROMURLDIALOG_H
|
||||||
|
|||||||
@@ -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;
|
if (id != id_) return;
|
||||||
id_ = 0;
|
id_ = 0;
|
||||||
|
|
||||||
if (!result.album_cover.image.isNull()) {
|
if (result && !result->album_cover->image.isNull()) {
|
||||||
temp_cover_ = std::make_unique<QTemporaryFile>(temp_file_pattern_);
|
temp_cover_ = std::make_unique<QTemporaryFile>(temp_file_pattern_);
|
||||||
temp_cover_->setAutoRemove(true);
|
temp_cover_->setAutoRemove(true);
|
||||||
if (temp_cover_->open()) {
|
if (temp_cover_->open()) {
|
||||||
if (result.album_cover.image.save(temp_cover_->fileName(), "JPEG")) {
|
if (result->album_cover->image.save(temp_cover_->fileName(), "JPEG")) {
|
||||||
result.temp_cover_url = QUrl::fromLocalFile(temp_cover_->fileName());
|
result->temp_cover_url = QUrl::fromLocalFile(temp_cover_->fileName());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
qLog(Error) << "Failed to save cover image to" << temp_cover_->fileName() << temp_cover_->errorString();
|
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;
|
QUrl thumbnail_url;
|
||||||
if (!result.image_thumbnail.isNull()) {
|
if (result && !result->image_thumbnail.isNull()) {
|
||||||
temp_cover_thumbnail_ = std::make_unique<QTemporaryFile>(temp_file_pattern_);
|
temp_cover_thumbnail_ = std::make_unique<QTemporaryFile>(temp_file_pattern_);
|
||||||
temp_cover_thumbnail_->setAutoRemove(true);
|
temp_cover_thumbnail_->setAutoRemove(true);
|
||||||
if (temp_cover_thumbnail_->open()) {
|
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());
|
thumbnail_url = QUrl::fromLocalFile(temp_cover_thumbnail_->fileName());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -108,11 +108,11 @@ void CurrentAlbumCoverLoader::TempAlbumCoverLoaded(const quint64 id, AlbumCoverL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.updated) {
|
if (result && result->updated) {
|
||||||
last_song_.set_art_manual(result.album_cover.cover_url);
|
last_song_.set_art_manual(result->album_cover->cover_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit AlbumCoverLoaded(last_song_, result);
|
emit AlbumCoverLoaded(last_song_, result);
|
||||||
emit ThumbnailLoaded(last_song_, thumbnail_url, result.image_thumbnail);
|
emit ThumbnailLoaded(last_song_, thumbnail_url, result->image_thumbnail);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,11 +52,11 @@ class CurrentAlbumCoverLoader : public QObject {
|
|||||||
void LoadAlbumCover(const Song &song);
|
void LoadAlbumCover(const Song &song);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void AlbumCoverLoaded(Song song, AlbumCoverLoaderResult result);
|
void AlbumCoverLoaded(Song song, AlbumCoverLoaderResultPtr result);
|
||||||
void ThumbnailLoaded(Song song, QUrl thumbnail_uri, QImage image);
|
void ThumbnailLoaded(Song song, QUrl thumbnail_uri, const QImage &image);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void TempAlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResult result);
|
void TempAlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Application *app_;
|
Application *app_;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
@@ -341,7 +342,7 @@ bool EditTagDialog::eventFilter(QObject *o, QEvent *e) {
|
|||||||
if (event->mimeData()->hasImage()) {
|
if (event->mimeData()->hasImage()) {
|
||||||
QImage image = qvariant_cast<QImage>(event->mimeData()->imageData());
|
QImage image = qvariant_cast<QImage>(event->mimeData()->imageData());
|
||||||
if (!image.isNull()) {
|
if (!image.isNull()) {
|
||||||
UpdateCover(UpdateCoverAction::New, AlbumCoverImageResult(image));
|
UpdateCover(UpdateCoverAction::New, std::make_shared<AlbumCoverImageResult>(image));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -637,10 +638,10 @@ void EditTagDialog::SelectionChanged() {
|
|||||||
bool lyrics_enabled = false;
|
bool lyrics_enabled = false;
|
||||||
for (const QModelIndex &idx : indexes) {
|
for (const QModelIndex &idx : indexes) {
|
||||||
if (data_[idx.row()].cover_action_ == UpdateCoverAction::None) {
|
if (data_[idx.row()].cover_action_ == UpdateCoverAction::None) {
|
||||||
data_[idx.row()].cover_result_ = AlbumCoverImageResult();
|
data_[idx.row()].cover_result_ = std::make_shared<AlbumCoverImageResult>();
|
||||||
}
|
}
|
||||||
const Song &song = data_[idx.row()].original_;
|
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;
|
action_different = true;
|
||||||
}
|
}
|
||||||
if (data_[idx.row()].cover_action_ != first_cover_action ||
|
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_) {
|
if (id == tags_cover_art_id_) {
|
||||||
ui_->tags_art->clear();
|
ui_->tags_art->clear();
|
||||||
bool enable_change_art = false;
|
bool enable_change_art = false;
|
||||||
if (result.success && !result.image_scaled.isNull() && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset) {
|
if (result->success && !result->image_scaled.isNull() && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset) {
|
||||||
ui_->tags_art->setPixmap(QPixmap::fromImage(result.image_scaled));
|
ui_->tags_art->setPixmap(QPixmap::fromImage(result->image_scaled));
|
||||||
for (const QModelIndex &idx : ui_->song_list->selectionModel()->selectedIndexes()) {
|
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();
|
enable_change_art = data_[idx.row()].original_.is_collection_song();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui_->tags_art->setPixmap(QPixmap::fromImage(image_no_cover_thumbnail_));
|
ui_->tags_art->setPixmap(QPixmap::fromImage(image_no_cover_thumbnail_));
|
||||||
for (const QModelIndex &idx : ui_->song_list->selectionModel()->selectedIndexes()) {
|
for (const QModelIndex &idx : ui_->song_list->selectionModel()->selectedIndexes()) {
|
||||||
data_[idx.row()].cover_result_ = AlbumCoverImageResult();
|
data_[idx.row()].cover_result_ = std::make_shared<AlbumCoverImageResult>();
|
||||||
enable_change_art = data_[idx.row()].original_.is_collection_song();
|
enable_change_art = data_[idx.row()].original_.is_collection_song();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tags_cover_art_id_ = -1;
|
tags_cover_art_id_ = -1;
|
||||||
album_cover_choice_controller_->show_cover_action()->setEnabled(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_->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_->delete_cover_action()->setEnabled(enable_change_art && result->success && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (id == summary_cover_art_id_) {
|
else if (id == summary_cover_art_id_) {
|
||||||
if (result.success && !result.image_scaled.isNull() && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset) {
|
if (result->success && !result->image_scaled.isNull() && result->type != AlbumCoverLoaderResult::Type::ManuallyUnset) {
|
||||||
ui_->summary_art->setPixmap(QPixmap::fromImage(result.image_scaled));
|
ui_->summary_art->setPixmap(QPixmap::fromImage(result->image_scaled));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ui_->summary_art->setPixmap(QPixmap::fromImage(image_no_cover_thumbnail_));
|
ui_->summary_art->setPixmap(QPixmap::fromImage(image_no_cover_thumbnail_));
|
||||||
@@ -980,8 +981,8 @@ void EditTagDialog::LoadCoverFromFile() {
|
|||||||
Song *song = GetFirstSelected();
|
Song *song = GetFirstSelected();
|
||||||
if (!song) return;
|
if (!song) return;
|
||||||
|
|
||||||
AlbumCoverImageResult result = album_cover_choice_controller_->LoadImageFromFile(song);
|
AlbumCoverImageResultPtr result = album_cover_choice_controller_->LoadImageFromFile(song);
|
||||||
if (result.is_valid()) UpdateCover(UpdateCoverAction::New, result);
|
if (result && result->is_valid()) UpdateCover(UpdateCoverAction::New, result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -998,8 +999,8 @@ void EditTagDialog::LoadCoverFromURL() {
|
|||||||
|
|
||||||
if (ui_->song_list->selectionModel()->selectedIndexes().isEmpty()) return;
|
if (ui_->song_list->selectionModel()->selectedIndexes().isEmpty()) return;
|
||||||
|
|
||||||
AlbumCoverImageResult result = album_cover_choice_controller_->LoadImageFromURL();
|
AlbumCoverImageResultPtr result = album_cover_choice_controller_->LoadImageFromURL();
|
||||||
if (result.is_valid()) UpdateCover(UpdateCoverAction::New, result);
|
if (result && result->is_valid()) UpdateCover(UpdateCoverAction::New, result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1008,8 +1009,8 @@ void EditTagDialog::SearchForCover() {
|
|||||||
Song *song = GetFirstSelected();
|
Song *song = GetFirstSelected();
|
||||||
if (!song) return;
|
if (!song) return;
|
||||||
|
|
||||||
AlbumCoverImageResult result = album_cover_choice_controller_->SearchForImage(song);
|
AlbumCoverImageResultPtr result = album_cover_choice_controller_->SearchForImage(song);
|
||||||
if (result.is_valid()) UpdateCover(UpdateCoverAction::New, result);
|
if (result && result->is_valid()) UpdateCover(UpdateCoverAction::New, result);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1046,11 +1047,11 @@ void EditTagDialog::ShowCover() {
|
|||||||
|
|
||||||
if (ui_->song_list->selectionModel()->selectedIndexes().isEmpty()) return;
|
if (ui_->song_list->selectionModel()->selectedIndexes().isEmpty()) return;
|
||||||
const Data &first_data = data_[ui_->song_list->selectionModel()->selectedIndexes().first().row()];
|
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();
|
const QModelIndexList indexes = ui_->song_list->selectionModel()->selectedIndexes();
|
||||||
if (indexes.isEmpty()) return;
|
if (indexes.isEmpty()) return;
|
||||||
@@ -1165,8 +1166,8 @@ void EditTagDialog::SaveData() {
|
|||||||
if ((!ref.current_.effective_albumartist().isEmpty() && !ref.current_.album().isEmpty()) &&
|
if ((!ref.current_.effective_albumartist().isEmpty() && !ref.current_.album().isEmpty()) &&
|
||||||
(!ui_->checkbox_embedded_cover->isChecked() || !ref.original_.save_embedded_cover_supported())) {
|
(!ui_->checkbox_embedded_cover->isChecked() || !ref.original_.save_embedded_cover_supported())) {
|
||||||
QUrl cover_url;
|
QUrl cover_url;
|
||||||
if (!ref.cover_result_.cover_url.isEmpty() && ref.cover_result_.cover_url.isLocalFile() && QFile::exists(ref.cover_result_.cover_url.toLocalFile())) {
|
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;
|
cover_url = ref.cover_result_->cover_url;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QString cover_hash = CoverUtils::Sha1CoverHash(ref.current_.effective_albumartist(), ref.current_.album()).toHex();
|
QString cover_hash = CoverUtils::Sha1CoverHash(ref.current_.effective_albumartist(), ref.current_.album()).toHex();
|
||||||
@@ -1223,9 +1224,9 @@ void EditTagDialog::SaveData() {
|
|||||||
TagReaderClient::SaveCoverOptions savecover_options;
|
TagReaderClient::SaveCoverOptions savecover_options;
|
||||||
savecover_options.enabled = save_embedded_cover;
|
savecover_options.enabled = save_embedded_cover;
|
||||||
if (save_embedded_cover && ref.cover_action_ == UpdateCoverAction::New) {
|
if (save_embedded_cover && ref.cover_action_ == UpdateCoverAction::New) {
|
||||||
if (!ref.cover_result_.image.isNull()) {
|
if (!ref.cover_result_->image.isNull()) {
|
||||||
savecover_options.is_jpeg = ref.cover_result_.is_jpeg();
|
savecover_options.is_jpeg = ref.cover_result_->is_jpeg();
|
||||||
savecover_options.cover_data = ref.cover_result_.image_data;
|
savecover_options.cover_data = ref.cover_result_->image_data;
|
||||||
}
|
}
|
||||||
else if (!embedded_cover_from_file.isEmpty()) {
|
else if (!embedded_cover_from_file.isEmpty()) {
|
||||||
savecover_options.cover_filename = embedded_cover_from_file;
|
savecover_options.cover_filename = embedded_cover_from_file;
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class EditTagDialog : public QDialog {
|
|||||||
New
|
New
|
||||||
};
|
};
|
||||||
struct Data {
|
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<AlbumCoverImageResult>()) {}
|
||||||
|
|
||||||
static QVariant value(const Song &song, const QString &id);
|
static QVariant value(const Song &song, const QString &id);
|
||||||
QVariant original_value(const QString &id) const { return value(original_, id); }
|
QVariant original_value(const QString &id) const { return value(original_, id); }
|
||||||
@@ -104,7 +104,7 @@ class EditTagDialog : public QDialog {
|
|||||||
Song original_;
|
Song original_;
|
||||||
Song current_;
|
Song current_;
|
||||||
UpdateCoverAction cover_action_;
|
UpdateCoverAction cover_action_;
|
||||||
AlbumCoverImageResult cover_result_;
|
AlbumCoverImageResultPtr cover_result_;
|
||||||
};
|
};
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
@@ -120,7 +120,7 @@ class EditTagDialog : public QDialog {
|
|||||||
void FetchTag();
|
void FetchTag();
|
||||||
void FetchTagSongChosen(const Song &original_song, const Song &new_metadata);
|
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 LoadCoverFromFile();
|
||||||
void SaveCoverToFile();
|
void SaveCoverToFile();
|
||||||
@@ -147,7 +147,7 @@ class EditTagDialog : public QDialog {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Song *GetFirstSelected();
|
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 DoesValueVary(const QModelIndexList &sel, const QString &id) const;
|
||||||
bool IsValueModified(const QModelIndexList &sel, const QString &id) const;
|
bool IsValueModified(const QModelIndexList &sel, const QString &id) const;
|
||||||
|
|||||||
@@ -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;
|
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;
|
QModelIndex idx = cover_loader_task.first;
|
||||||
QString key = cover_loader_task.second;
|
QString key = cover_loader_task.second;
|
||||||
|
|
||||||
if (albumcover_result.success && !albumcover_result.image_scaled.isNull()) {
|
if (albumcover_result && albumcover_result->success && !albumcover_result->image_scaled.isNull()) {
|
||||||
QPixmap pixmap = QPixmap::fromImage(albumcover_result.image_scaled);
|
QPixmap pixmap = QPixmap::fromImage(albumcover_result->image_scaled);
|
||||||
if (!pixmap.isNull()) {
|
if (!pixmap.isNull()) {
|
||||||
QPixmapCache::insert(key, pixmap);
|
QPixmapCache::insert(key, pixmap);
|
||||||
}
|
}
|
||||||
if (idx.isValid()) {
|
if (idx.isValid()) {
|
||||||
QStandardItem *item = front_model_->itemFromIndex(idx);
|
QStandardItem *item = front_model_->itemFromIndex(idx);
|
||||||
if (item) {
|
if (item) {
|
||||||
item->setData(albumcover_result.image_scaled, Qt::DecorationRole);
|
item->setData(albumcover_result->image_scaled, Qt::DecorationRole);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ class InternetSearchView : public QWidget {
|
|||||||
void GroupByClicked(QAction *action);
|
void GroupByClicked(QAction *action);
|
||||||
void SetGroupBy(const CollectionModel::Grouping g);
|
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:
|
public slots:
|
||||||
void ReloadSettings();
|
void ReloadSettings();
|
||||||
|
|||||||
@@ -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.
|
// 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();
|
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()))) {
|
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.";
|
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);
|
item->SetArtManual(result->album_cover->cover_url);
|
||||||
ScheduleSaveAsync();
|
ScheduleSaveAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ class Playlist : public QAbstractListModel {
|
|||||||
void RepopulateDynamicPlaylist();
|
void RepopulateDynamicPlaylist();
|
||||||
void TurnOffDynamicPlaylist();
|
void TurnOffDynamicPlaylist();
|
||||||
|
|
||||||
void AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &result);
|
void AlbumCoverLoaded(const Song &song, AlbumCoverLoaderResultPtr result);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void RestoreFinished();
|
void RestoreFinished();
|
||||||
|
|||||||
@@ -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 (background_image_type_ == AppearanceSettingsPage::BackgroundImageType::Album) {
|
||||||
if (song.art_automatic().isEmpty() && song.art_manual().isEmpty()) {
|
if (song.art_automatic().isEmpty() && song.art_manual().isEmpty()) {
|
||||||
set_background_image(QImage());
|
set_background_image(QImage());
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ class PlaylistView : public QTreeView {
|
|||||||
void Playing();
|
void Playing();
|
||||||
void Stopped();
|
void Stopped();
|
||||||
void SongChanged(const Song &song);
|
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 DynamicModeChanged(const bool dynamic);
|
||||||
void SetRatingLockStatus(const bool state);
|
void SetRatingLockStatus(const bool state);
|
||||||
void RatingHoverIn(const QModelIndex &idx, const QPoint pos);
|
void RatingHoverIn(const QModelIndex &idx, const QPoint pos);
|
||||||
|
|||||||
@@ -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;
|
if (!pending_art_.contains(id)) return;
|
||||||
|
|
||||||
@@ -319,11 +319,11 @@ void RadioModel::AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult
|
|||||||
|
|
||||||
pending_cache_keys_.remove(cache_key);
|
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));
|
QPixmapCache::insert(cache_key, ServiceIcon(item));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
QPixmapCache::insert(cache_key, QPixmap::fromImage(result.image_scaled));
|
QPixmapCache::insert(cache_key, QPixmap::fromImage(result->image_scaled));
|
||||||
}
|
}
|
||||||
|
|
||||||
const QModelIndex idx = ItemToIndex(item);
|
const QModelIndex idx = ItemToIndex(item);
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class RadioModel : public SimpleTreeModel<RadioItem> {
|
|||||||
QString SortText(QString text);
|
QString SortText(QString text);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void AlbumCoverLoaded(const quint64 id, const AlbumCoverLoaderResult &result);
|
void AlbumCoverLoaded(const quint64 id, AlbumCoverLoaderResultPtr result);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int kTreeIconSize;
|
static const int kTreeIconSize;
|
||||||
|
|||||||
Reference in New Issue
Block a user