From 98ad9dbda6d08c760c62017f8013c493bea38013 Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 30 Dec 2013 23:50:57 +0100 Subject: [PATCH] Add possibility to download album covers automatically when playing a track without one. To activate: right click on now playing widget and select "Search automatically". --- src/ui/albumcoverchoicecontroller.cpp | 28 +++++++++++++ src/ui/albumcoverchoicecontroller.h | 15 +++++++ src/widgets/nowplayingwidget.cpp | 59 ++++++++++++++++++++++++++- src/widgets/nowplayingwidget.h | 7 ++++ 4 files changed, 108 insertions(+), 1 deletion(-) diff --git a/src/ui/albumcoverchoicecontroller.cpp b/src/ui/albumcoverchoicecontroller.cpp index 1b762eaca..224bee055 100644 --- a/src/ui/albumcoverchoicecontroller.cpp +++ b/src/ui/albumcoverchoicecontroller.cpp @@ -63,6 +63,10 @@ AlbumCoverChoiceController::AlbumCoverChoiceController(QWidget* parent) unset_cover_ = new QAction(IconLoader::Load("list-remove"), tr("Unset cover"), this); show_cover_ = new QAction(IconLoader::Load("zoom-in"), tr("Show fullsize..."), this); + search_cover_auto_ = new QAction(IconLoader::Load("find"), tr("Search automatically"), this); + search_cover_auto_->setCheckable(true); + search_cover_auto_->setChecked(false); + separator_ = new QAction(this); separator_->setSeparator(true); } @@ -77,6 +81,9 @@ void AlbumCoverChoiceController::SetApplication(Application* app) { cover_fetcher_ = new AlbumCoverFetcher(app_->cover_providers(), this); cover_searcher_ = new AlbumCoverSearcher(QIcon(":/nocover.png"), app, this); cover_searcher_->Init(cover_fetcher_); + + connect(cover_fetcher_, SIGNAL(AlbumCoverFetched(quint64,QImage,CoverSearchStatistics)), + this, SLOT(AlbumCoverFetched(quint64,QImage,CoverSearchStatistics))); } QList AlbumCoverChoiceController::GetAllActions() { @@ -204,6 +211,27 @@ void AlbumCoverChoiceController::ShowCover(const Song& song) { dialog->show(); } +void AlbumCoverChoiceController::SearchCoverAutomatically(const Song& song) { + qint64 id = cover_fetcher_->FetchAlbumCover(song.artist(), song.album()); + cover_fetching_tasks_[id] = song; +} + +void AlbumCoverChoiceController::AlbumCoverFetched(quint64 id, + const QImage &image, + const CoverSearchStatistics &statistics) { + Song song; + if (cover_fetching_tasks_.contains(id)) { + song = cover_fetching_tasks_.take(id); + } + + if (!image.isNull()) { + QString cover = SaveCoverInCache(song.artist(), song.album(), image); + SaveCover(&song, cover); + } + + emit AutomaticCoverSearchDone(); +} + void AlbumCoverChoiceController::SaveCover(Song* song, const QString &cover) { if(song->is_valid() && song->id() != -1) { song->set_art_manual(cover); diff --git a/src/ui/albumcoverchoicecontroller.h b/src/ui/albumcoverchoicecontroller.h index c3ed2d421..7da216e66 100644 --- a/src/ui/albumcoverchoicecontroller.h +++ b/src/ui/albumcoverchoicecontroller.h @@ -27,6 +27,7 @@ class AlbumCoverFetcher; class AlbumCoverSearcher; class Application; class CoverFromURLDialog; +class CoverSearchStatistics; class QFileDialog; class Song; @@ -52,6 +53,7 @@ class AlbumCoverChoiceController : public QWidget { QAction* search_for_cover_action() const { return search_for_cover_; } QAction* unset_cover_action() const { return unset_cover_; } QAction* show_cover_action() const { return show_cover_; } + QAction* search_cover_auto_action() const { return search_cover_auto_; } // Returns QAction* for every operation implemented by this controller. // The list contains QAction* for: @@ -91,6 +93,9 @@ class AlbumCoverChoiceController : public QWidget { // Shows the cover of given song in it's original size. void ShowCover(const Song& song); + // Search for covers automatically + void SearchCoverAutomatically(const Song& song); + // Saves the chosen cover as manual cover path of this song in library. void SaveCover(Song* song, const QString& cover); @@ -103,6 +108,13 @@ class AlbumCoverChoiceController : public QWidget { static bool CanAcceptDrag(const QDragEnterEvent* e); +signals: + void AutomaticCoverSearchDone(); + +private slots: + void AlbumCoverFetched(quint64 id, const QImage& image, + const CoverSearchStatistics& statistics); + private: QString GetInitialPathForFileDialog(const Song& song, const QString& filename); @@ -124,6 +136,9 @@ private: QAction* search_for_cover_; QAction* unset_cover_; QAction* show_cover_; + QAction* search_cover_auto_; + + QMap cover_fetching_tasks_; }; #endif // ALBUMCOVERCHOICECONTROLLER_H diff --git a/src/widgets/nowplayingwidget.cpp b/src/widgets/nowplayingwidget.cpp index 29d81eb6f..13d62e861 100644 --- a/src/widgets/nowplayingwidget.cpp +++ b/src/widgets/nowplayingwidget.cpp @@ -72,6 +72,7 @@ NowPlayingWidget::NowPlayingWidget(QWidget* parent) details_(new QTextDocument(this)), previous_track_opacity_(0.0), bask_in_his_glory_action_(NULL), + downloading_covers_(false), aww_(false), kittens_(NULL), pending_kitten_(0) @@ -80,6 +81,7 @@ NowPlayingWidget::NowPlayingWidget(QWidget* parent) QSettings s; s.beginGroup(kSettingsGroup); mode_ = Mode(s.value("mode", SmallSongDetails).toInt()); + album_cover_choice_controller_->search_cover_auto_action()->setChecked(s.value("search_for_cover_auto", false).toBool()); // Accept drops for setting album art setAcceptDrops(true); @@ -96,6 +98,9 @@ NowPlayingWidget::NowPlayingWidget(QWidget* parent) QList actions = album_cover_choice_controller_->GetAllActions(); + // Here we add the search automatically action, too! + actions.append(album_cover_choice_controller_->search_cover_auto_action()); + connect(album_cover_choice_controller_->cover_from_file_action(), SIGNAL(triggered()), this, SLOT(LoadCoverFromFile())); connect(album_cover_choice_controller_->cover_to_file_action(), @@ -108,6 +113,8 @@ NowPlayingWidget::NowPlayingWidget(QWidget* parent) SIGNAL(triggered()), this, SLOT(UnsetCover())); connect(album_cover_choice_controller_->show_cover_action(), SIGNAL(triggered()), this, SLOT(ShowCover())); + connect(album_cover_choice_controller_->search_cover_auto_action(), + SIGNAL(triggered()), this, SLOT(SearchCoverAutomatically())); menu_->addActions(actions); menu_->addSeparator(); @@ -129,6 +136,9 @@ NowPlayingWidget::NowPlayingWidget(QWidget* parent) fade_animation_->setDirection(QTimeLine::Backward); // 1.0 -> 0.0 UpdateHeight(); + + connect(album_cover_choice_controller_, SIGNAL(AutomaticCoverSearchDone()), + this, SLOT(AutomaticCoverSearchDone())); } NowPlayingWidget::~NowPlayingWidget() { @@ -233,9 +243,10 @@ void NowPlayingWidget::KittenLoaded(quint64 id, const QImage& image) { } } -void NowPlayingWidget::AlbumArtLoaded(const Song& metadata, const QString&, +void NowPlayingWidget::AlbumArtLoaded(const Song& metadata, const QString& uri, const QImage& image) { metadata_ = metadata; + downloading_covers_ = false; if (aww_) { pending_kitten_ = kittens_->LoadKitten(app_->current_art_loader()->options()); @@ -243,6 +254,9 @@ void NowPlayingWidget::AlbumArtLoaded(const Song& metadata, const QString&, } SetImage(image); + + // Search for cover automatically? + GetCoverAutomatically(); } void NowPlayingWidget::SetImage(const QImage& image) { @@ -301,6 +315,9 @@ void NowPlayingWidget::DrawContents(QPainter *p) { } else { // Draw the cover p->drawPixmap(0, 0, small_ideal_height_, small_ideal_height_, cover_); + if (downloading_covers_) { + p->drawPixmap(small_ideal_height_ - 18, 6, 16, 16, spinner_animation_->currentPixmap()); + } } // Draw the details @@ -321,6 +338,9 @@ void NowPlayingWidget::DrawContents(QPainter *p) { p->drawPixmap(x_offset, kTopBorder, total_size, total_size, hypnotoad_->currentPixmap()); } else { p->drawPixmap(x_offset, kTopBorder, total_size, total_size, cover_); + if (downloading_covers_) { + p->drawPixmap(total_size - 31, 40, 16, 16, spinner_animation_->currentPixmap()); + } } // Work out how high the text is going to be @@ -454,6 +474,15 @@ void NowPlayingWidget::ShowCover() { album_cover_choice_controller_->ShowCover(metadata_); } +void NowPlayingWidget::SearchCoverAutomatically() { + QSettings s; + s.beginGroup(kSettingsGroup); + s.setValue("search_for_cover_auto", album_cover_choice_controller_->search_cover_auto_action()->isChecked()); + + // Search for cover automatically? + GetCoverAutomatically(); +} + void NowPlayingWidget::Bask() { big_hypnotoad_.reset(new FullscreenHypnotoad); big_hypnotoad_->showFullScreen(); @@ -472,3 +501,31 @@ void NowPlayingWidget::dropEvent(QDropEvent* e) { QWidget::dropEvent(e); } + +bool NowPlayingWidget::GetCoverAutomatically() { + // Search for cover automatically? + bool search = album_cover_choice_controller_->search_cover_auto_action()->isChecked() && + !metadata_.has_manually_unset_cover() && + metadata_.art_automatic().isEmpty() && + metadata_.art_manual().isEmpty(); + + if (search) { + qLog(Debug) << "GetCoverAutomatically"; + downloading_covers_ = true; + album_cover_choice_controller_->SearchCoverAutomatically(metadata_); + + // Show a spinner animation + spinner_animation_.reset(new QMovie(":/spinner.gif", QByteArray(), this)); + connect(spinner_animation_.get(), SIGNAL(updated(const QRect&)), SLOT(update())); + spinner_animation_->start(); + update(); + } + + return search; +} + +void NowPlayingWidget::AutomaticCoverSearchDone() { + downloading_covers_ = false; + spinner_animation_.reset(); + update(); +} diff --git a/src/widgets/nowplayingwidget.h b/src/widgets/nowplayingwidget.h index 498e1a44e..b7dd4da1d 100644 --- a/src/widgets/nowplayingwidget.h +++ b/src/widgets/nowplayingwidget.h @@ -99,9 +99,12 @@ private slots: void SearchForCover(); void UnsetCover(); void ShowCover(); + void SearchCoverAutomatically(); void Bask(); + void AutomaticCoverSearchDone(); + private: void CreateModeAction(Mode mode, const QString& text, QActionGroup* group, QSignalMapper* mapper); @@ -110,6 +113,7 @@ private: void DrawContents(QPainter* p); void SetImage(const QImage& image); void ScaleCover(); + bool GetCoverAutomatically(); private: Application* app_; @@ -144,6 +148,9 @@ private: boost::scoped_ptr hypnotoad_; boost::scoped_ptr big_hypnotoad_; + boost::scoped_ptr spinner_animation_; + bool downloading_covers_; + bool aww_; KittenLoader* kittens_; quint64 pending_kitten_;