Add a dialog for manual searching of Last.fm album covers. Fixes issue #402

This commit is contained in:
David Sansome 2010-06-12 17:13:01 +00:00
parent 516f769a75
commit 36abad486b
36 changed files with 743 additions and 76 deletions

View File

@ -105,6 +105,7 @@ set(SOURCES
ui/addstreamdialog.cpp
ui/albumcovermanager.cpp
ui/albumcovermanagerlist.cpp
ui/albumcoversearcher.cpp
ui/edittagdialog.cpp
ui/equalizer.cpp
ui/globalshortcutgrabber.cpp
@ -203,6 +204,7 @@ set(HEADERS
ui/addstreamdialog.h
ui/albumcovermanager.h
ui/albumcovermanagerlist.h
ui/albumcoversearcher.h
ui/edittagdialog.h
ui/equalizer.h
ui/globalshortcutgrabber.h
@ -248,6 +250,7 @@ set(UI
ui/about.ui
ui/addstreamdialog.ui
ui/albumcovermanager.ui
ui/albumcoversearcher.ui
ui/edittagdialog.ui
ui/equalizer.ui
ui/globalshortcutgrabber.ui

View File

@ -43,15 +43,27 @@ quint64 AlbumCoverFetcher::FetchAlbumCover(
request.artist = artist_name;
request.id = next_id_ ++;
queued_requests_.enqueue(request);
AddRequest(request);
return request.id;
}
quint64 AlbumCoverFetcher::SearchForCovers(const QString &query) {
QueuedRequest request;
request.query = query;
request.id = next_id_ ++;
AddRequest(request);
return request.id;
}
void AlbumCoverFetcher::AddRequest(QueuedRequest req) {
queued_requests_.enqueue(req);
if (!request_starter_->isActive())
request_starter_->start();
if (active_requests_.count() < kMaxConcurrentRequests)
StartRequests();
return request.id;
}
void AlbumCoverFetcher::Clear() {
@ -68,12 +80,22 @@ void AlbumCoverFetcher::StartRequests() {
active_requests_.count() < kMaxConcurrentRequests) {
QueuedRequest request = queued_requests_.dequeue();
lastfm::Artist artist(request.artist);
lastfm::Album album(artist, request.album);
if (request.query.isEmpty()) {
lastfm::Artist artist(request.artist);
lastfm::Album album(artist, request.album);
QNetworkReply* reply = album.getInfo();
connect(reply, SIGNAL(finished()), SLOT(AlbumGetInfoFinished()));
active_requests_.insert(reply, request.id);
QNetworkReply* reply = album.getInfo();
connect(reply, SIGNAL(finished()), SLOT(AlbumGetInfoFinished()));
active_requests_.insert(reply, request.id);
} else {
QMap<QString, QString> params;
params["method"] = "album.search";
params["album"] = request.query;
QNetworkReply* reply = lastfm::ws::post(params);
connect(reply, SIGNAL(finished()), SLOT(AlbumSearchFinished()));
active_requests_.insert(reply, request.id);
}
}
}
@ -101,6 +123,38 @@ void AlbumCoverFetcher::AlbumGetInfoFinished() {
}
}
void AlbumCoverFetcher::AlbumSearchFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
reply->deleteLater();
quint64 id = active_requests_.take(reply);
if (reply->error() != QNetworkReply::NoError) {
qDebug() << "Error" << reply->error();
// TODO: retry request.
emit SearchFinished(id, SearchResults());
return;
}
try {
lastfm::XmlQuery query(lastfm::ws::parse(reply));
QList<lastfm::XmlQuery> elements = query["results"]["albummatches"].children("album");
SearchResults results;
foreach (const lastfm::XmlQuery& element, elements) {
SearchResult result;
result.album = element["name"].text();
result.artist = element["artist"].text();
result.image_url = element["image size=large"].text();
results << result;
}
emit SearchFinished(id, results);
} catch (std::runtime_error&) {
qDebug() << "Parse error";
emit SearchFinished(id, SearchResults());
}
}
void AlbumCoverFetcher::AlbumCoverFetchFinished() {
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
reply->deleteLater();

View File

@ -39,27 +39,40 @@ class AlbumCoverFetcher : public QObject {
AlbumCoverFetcher(NetworkAccessManager* network, QObject* parent = 0);
virtual ~AlbumCoverFetcher() {}
struct SearchResult {
QString artist;
QString album;
QString image_url;
};
typedef QList<SearchResult> SearchResults;
static const int kMaxConcurrentRequests;
quint64 SearchForCovers(const QString& query);
quint64 FetchAlbumCover(const QString& artist, const QString& album);
void Clear();
signals:
void AlbumCoverFetched(quint64, const QImage& cover);
void SearchFinished(quint64, const AlbumCoverFetcher::SearchResults& results);
private slots:
void AlbumGetInfoFinished();
void AlbumCoverFetchFinished();
void StartRequests();
void AlbumSearchFinished();
private:
struct QueuedRequest {
quint64 id;
QString query;
QString artist;
QString album;
};
void AddRequest(const QueuedRequest req);
QNetworkAccessManager* network_;
quint64 next_id_;

View File

@ -113,6 +113,9 @@
<item>
<widget class="QWidget" name="busy" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_5">
<property name="text">

View File

@ -1107,18 +1107,24 @@ msgstr ""
msgid "Fetch automatically"
msgstr ""
msgid "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr ""
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr ""
msgid "Fetch Missing Covers"
msgstr ""
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr ""

View File

@ -1111,18 +1111,24 @@ msgstr "Zobrazit v plné velikosti..."
msgid "Fetch automatically"
msgstr "Automaticky stáhnout"
msgid "Choose manual cover..."
msgstr "Vybrat obal ručně..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Odebrat obal"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "POhled"
msgid "Fetch Missing Covers"
msgstr "Stáhnout chybějící obaly"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Upravit informaci o skladbách"
@ -1429,6 +1435,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Vybrat obal ručně..."
#~ msgid "Show section"
#~ msgstr "Zobrazit skeci"

View File

@ -1114,18 +1114,24 @@ msgstr "Vis i fuld størrelse..."
msgid "Fetch automatically"
msgstr "Hent automatisk"
msgid "Choose manual cover..."
msgstr "Vælg omslag manuelt..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Fravælg omslag"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Vis"
msgid "Fetch Missing Covers"
msgstr "Hent manglende omslag"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Redigér sporinformation"
@ -1432,6 +1438,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Vælg omslag manuelt..."
#~ msgid "Show section"
#~ msgstr "Vis sektion"

View File

@ -1113,18 +1113,24 @@ msgstr "Vollbild..."
msgid "Fetch automatically"
msgstr "Cover automatisch holen"
msgid "Choose manual cover..."
msgstr "Cover selbst auswählen..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Cover löschen"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Ansicht"
msgid "Fetch Missing Covers"
msgstr "Fehlende Cover holen"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Metadaten bearbeiten"
@ -1433,6 +1439,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Cover selbst auswählen..."
#~ msgid "Show section"
#~ msgstr "Spalten"

View File

@ -1117,18 +1117,24 @@ msgstr "Εμφάνισε σε πλήρες μέγεθος..."
msgid "Fetch automatically"
msgstr "Αυτόματο κατέβασμα"
msgid "Choose manual cover..."
msgstr "Επιλογή εξώφυλλου χειροκίνητα..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Αφαίρεση εξώφυλλου"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Προβολή"
msgid "Fetch Missing Covers"
msgstr "Κατέβασμα εξώφυλλων που λείπουν"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Τροποποίηση πληροφοριών κομματιού"
@ -1435,6 +1441,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Επιλογή εξώφυλλου χειροκίνητα..."
#~ msgid "Show section"
#~ msgstr "Εμφάνιση τμήματος"

View File

@ -1112,18 +1112,24 @@ msgstr "Show fullsize..."
msgid "Fetch automatically"
msgstr "Fetch automatically"
msgid "Choose manual cover..."
msgstr "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Unset cover"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "View"
msgid "Fetch Missing Covers"
msgstr "Fetch Missing Covers"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Edit track information"
@ -1430,6 +1436,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Choose manual cover..."
#~ msgid "Show section"
#~ msgstr "Show section"

View File

@ -1109,18 +1109,24 @@ msgstr "Show fullsize..."
msgid "Fetch automatically"
msgstr "Fetch automatically"
msgid "Choose manual cover..."
msgstr "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Unset cover"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "View"
msgid "Fetch Missing Covers"
msgstr "Fetch Missing Covers"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Edit track information"
@ -1427,6 +1433,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Choose manual cover..."
#~ msgid "Show section"
#~ msgstr "Show section"

View File

@ -1121,18 +1121,24 @@ msgstr "Mostrar carátula..."
msgid "Fetch automatically"
msgstr "Obtener carátula"
msgid "Choose manual cover..."
msgstr "Establecer carátula personalizada..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Quitar carátula"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Ver"
msgid "Fetch Missing Covers"
msgstr "Obtener Carátulas Faltantes"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Editar información de la pista"
@ -1441,6 +1447,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Establecer carátula personalizada..."
#~ msgid "Show section"
#~ msgstr "Mostrar columna"

View File

@ -1107,18 +1107,24 @@ msgstr ""
msgid "Fetch automatically"
msgstr ""
msgid "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr ""
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr ""
msgid "Fetch Missing Covers"
msgstr ""
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr ""

View File

@ -1117,18 +1117,24 @@ msgstr "Afficher en taille réelle..."
msgid "Fetch automatically"
msgstr "Récupérer automatiquement"
msgid "Choose manual cover..."
msgstr "Choisir une jaquette manuellement..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Enlever la jaquette"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Vue"
msgid "Fetch Missing Covers"
msgstr "Récupérer les jaquettes manquantes"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Modifier la description de la piste"
@ -1437,6 +1443,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Choisir une jaquette manuellement..."
#~ msgid "Show section"
#~ msgstr "Montrer la colonne"

View File

@ -1109,18 +1109,24 @@ msgstr ""
msgid "Fetch automatically"
msgstr ""
msgid "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr ""
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr ""
msgid "Fetch Missing Covers"
msgstr ""
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr ""

View File

@ -1118,18 +1118,24 @@ msgstr "Mostra a dimensioni originali..."
msgid "Fetch automatically"
msgstr "Scarica automaticamente"
msgid "Choose manual cover..."
msgstr "Scelta manuale copertina..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Rimuovi copertina"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Visualizza"
msgid "Fetch Missing Covers"
msgstr "Scarica copertine mancanti"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Modifica informazioni della traccia"
@ -1438,6 +1444,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Scelta manuale copertina..."
#~ msgid "Show section"
#~ msgstr "Mostra sezione"

View File

@ -1109,18 +1109,24 @@ msgstr ""
msgid "Fetch automatically"
msgstr ""
msgid "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr ""
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr ""
msgid "Fetch Missing Covers"
msgstr ""
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr ""

View File

@ -1111,18 +1111,24 @@ msgstr "Vis i fullskjerm..."
msgid "Fetch automatically"
msgstr "Hent automatisk"
msgid "Choose manual cover..."
msgstr "Velg omslag manuelt..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Fjern omslaget"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Vis"
msgid "Fetch Missing Covers"
msgstr "Hent manglende omslag"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Redigér informasjon om sporet"
@ -1429,6 +1435,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Velg omslag manuelt..."
#~ msgid "Show section"
#~ msgstr "Vis del"

View File

@ -1107,18 +1107,24 @@ msgstr ""
msgid "Fetch automatically"
msgstr ""
msgid "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr ""
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Afichatge"
msgid "Fetch Missing Covers"
msgstr ""
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr ""

View File

@ -1109,18 +1109,24 @@ msgstr "Pokaż w pełnej wielkości..."
msgid "Fetch automatically"
msgstr "Pobierz automatycznie"
msgid "Choose manual cover..."
msgstr "Wybierz okładkę ręcznie..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Usuń okładkę"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Pokaż"
msgid "Fetch Missing Covers"
msgstr "Pobierz brakujące okładki"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Edytuj informacje o utworze"
@ -1427,6 +1433,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Wybierz okładkę ręcznie..."
#~ msgid "Show section"
#~ msgstr "Pokaż sekcję"

View File

@ -1113,18 +1113,24 @@ msgstr "Mostar tamanho total..."
msgid "Fetch automatically"
msgstr "Obter automaticamente"
msgid "Choose manual cover..."
msgstr "Escolher uma capa manualmente..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Sem capa"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Ver"
msgid "Fetch Missing Covers"
msgstr "Obter as Capas em Falta"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Editar a informação da faixa"
@ -1432,6 +1438,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Escolher uma capa manualmente..."
#~ msgid "Show section"
#~ msgstr "Mostrar secção"

View File

@ -1117,18 +1117,24 @@ msgstr "Exibir tamanho real..."
msgid "Fetch automatically"
msgstr "Buscar automaticamente"
msgid "Choose manual cover..."
msgstr "Escolher capa manualmente"
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Capa não fixada"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Exibir"
msgid "Fetch Missing Covers"
msgstr "Buscar as Capas que Faltam"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Editar informações da faixa"
@ -1435,6 +1441,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Escolher capa manualmente"
#~ msgid "Show section"
#~ msgstr "Mostrar sessão"

View File

@ -1108,18 +1108,24 @@ msgstr ""
msgid "Fetch automatically"
msgstr "Obține automat"
msgid "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr ""
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr ""
msgid "Fetch Missing Covers"
msgstr "Obține copertele lipsă"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr ""

View File

@ -1113,18 +1113,24 @@ msgstr "Показать полный размер..."
msgid "Fetch automatically"
msgstr "Выбирать автоматически"
msgid "Choose manual cover..."
msgstr "Укажите обложку вручную..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Удалить обложку"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Просмотр"
msgid "Fetch Missing Covers"
msgstr "Выберете пропущенные обложки"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Редактировать информацию"
@ -1432,6 +1438,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Укажите обложку вручную..."
#~ msgid "Show section"
#~ msgstr "Показать секцию"

View File

@ -1114,18 +1114,24 @@ msgstr "Ukázať celú veľkosť..."
msgid "Fetch automatically"
msgstr "Získavať automaticky"
msgid "Choose manual cover..."
msgstr "Vybrať obal ručne..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Nenastavený obal"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Zobraziť"
msgid "Fetch Missing Covers"
msgstr "Získať chýbajúce obaly"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Upravť informácie o skladbe"
@ -1432,6 +1438,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Vybrať obal ručne..."
#~ msgid "Show section"
#~ msgstr "Zobraziť stĺpec"

View File

@ -1114,18 +1114,24 @@ msgstr "Visa full storlek..."
msgid "Fetch automatically"
msgstr "Hämta automatiskt"
msgid "Choose manual cover..."
msgstr "Välj manuellt omslag..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr "Ta bort omslag"
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr "Visa"
msgid "Fetch Missing Covers"
msgstr "Hämta saknade omslag"
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr "Redigera spårinformation"
@ -1432,6 +1438,9 @@ msgstr ""
msgid "Delay between visualisations"
msgstr ""
#~ msgid "Choose manual cover..."
#~ msgstr "Välj manuellt omslag..."
#~ msgid "Show section"
#~ msgstr "Visa kolumn"

View File

@ -1107,18 +1107,24 @@ msgstr ""
msgid "Fetch automatically"
msgstr ""
msgid "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr ""
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr ""
msgid "Fetch Missing Covers"
msgstr ""
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr ""

View File

@ -1107,18 +1107,24 @@ msgstr ""
msgid "Fetch automatically"
msgstr ""
msgid "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr ""
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr ""
msgid "Fetch Missing Covers"
msgstr ""
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr ""

View File

@ -1107,18 +1107,24 @@ msgstr ""
msgid "Fetch automatically"
msgstr ""
msgid "Choose manual cover..."
msgid "Load cover from disk..."
msgstr ""
msgid "Unset cover"
msgstr ""
msgid "Search for album covers..."
msgstr ""
msgid "View"
msgstr ""
msgid "Fetch Missing Covers"
msgstr ""
msgid "Search"
msgstr ""
msgid "Edit track information"
msgstr ""

View File

@ -15,6 +15,7 @@
*/
#include "albumcovermanager.h"
#include "albumcoversearcher.h"
#include "iconloader.h"
#include "ui_albumcovermanager.h"
#include "core/albumcoverfetcher.h"
@ -48,6 +49,7 @@ AlbumCoverManager::AlbumCoverManager(NetworkAccessManager* network,
network_(network),
cover_loader_(new BackgroundThreadImplementation<AlbumCoverLoader, AlbumCoverLoader>(this)),
cover_fetcher_(new AlbumCoverFetcher(network, this)),
cover_searcher_(new AlbumCoverSearcher(this)),
artist_icon_(IconLoader::Load("x-clementine-artist")),
all_artists_icon_(IconLoader::Load("x-clementine-album")),
context_menu_(new QMenu(this)),
@ -67,6 +69,7 @@ AlbumCoverManager::AlbumCoverManager(NetworkAccessManager* network,
ui_->clear->setIcon(IconLoader::Load("edit-clear-locationbar-ltr"));
ui_->view->setIcon(IconLoader::Load("view-choose"));
ui_->fetch->setIcon(IconLoader::Load("download"));
ui_->action_search_manual->setIcon(IconLoader::Load("download"));
ui_->action_add_to_playlist->setIcon(IconLoader::Load("media-playback-start"));
ui_->action_load->setIcon(IconLoader::Load("media-playback-start"));
@ -110,7 +113,7 @@ void AlbumCoverManager::Init() {
// Context menu
context_menu_->addAction(ui_->action_show_fullsize);
context_menu_->addAction(ui_->action_fetch);
context_menu_->addAction(ui_->action_search_manual);
context_menu_->addAction(ui_->action_choose_manual);
context_menu_->addSeparator();
context_menu_->addAction(ui_->action_unset_cover);
@ -136,6 +139,7 @@ void AlbumCoverManager::Init() {
connect(ui_->albums, SIGNAL(doubleClicked(QModelIndex)), SLOT(AlbumDoubleClicked(QModelIndex)));
connect(ui_->action_add_to_playlist, SIGNAL(triggered()), SLOT(AddSelectedToPlaylist()));
connect(ui_->action_load, SIGNAL(triggered()), SLOT(LoadSelectedToPlaylist()));
connect(ui_->action_search_manual, SIGNAL(triggered()), SLOT(SearchManual()));
// Restore settings
QSettings s;
@ -156,6 +160,8 @@ void AlbumCoverManager::CoverLoaderInitialised() {
cover_loader_->Worker()->SetDefaultOutputImage(QImage(":nocover.png"));
connect(cover_loader_->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage)),
SLOT(CoverImageLoaded(quint64,QImage)));
cover_searcher_->Init(cover_loader_->Worker(), cover_fetcher_);
}
void AlbumCoverManager::showEvent(QShowEvent *) {
@ -349,31 +355,7 @@ void AlbumCoverManager::AlbumCoverFetched(quint64 id, const QImage &image) {
} else {
got_covers_ ++;
const QString artist = item->data(Role_ArtistName).toString();
const QString album = item->data(Role_AlbumName).toString();
// Hash the artist and album into a filename for the image
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(artist.toLower().toUtf8().constData());
hash.addData(album.toLower().toUtf8().constData());
QString filename = hash.result().toHex() + ".jpg";
QString path = AlbumCoverLoader::ImageCacheDir() + "/" + filename;
// Make sure this directory exists first
QDir dir;
dir.mkdir(AlbumCoverLoader::ImageCacheDir());
// Save the image to disk
image.save(path, "JPG");
// Save the image in the database
backend_->UpdateManualAlbumArtAsync(artist, album, path);
// Update the icon in our list
quint64 id = cover_loader_->Worker()->LoadImageAsync(QString(), path);
item->setData(Role_PathManual, path);
cover_loading_tasks_[id] = item;
SaveAndSetCover(item, image);
}
if (cover_fetching_tasks_.isEmpty())
@ -382,6 +364,34 @@ void AlbumCoverManager::AlbumCoverFetched(quint64 id, const QImage &image) {
UpdateStatusText();
}
void AlbumCoverManager::SaveAndSetCover(QListWidgetItem *item, const QImage &image) {
const QString artist = item->data(Role_ArtistName).toString();
const QString album = item->data(Role_AlbumName).toString();
// Hash the artist and album into a filename for the image
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(artist.toLower().toUtf8().constData());
hash.addData(album.toLower().toUtf8().constData());
QString filename = hash.result().toHex() + ".jpg";
QString path = AlbumCoverLoader::ImageCacheDir() + "/" + filename;
// Make sure this directory exists first
QDir dir;
dir.mkdir(AlbumCoverLoader::ImageCacheDir());
// Save the image to disk
image.save(path, "JPG");
// Save the image in the database
backend_->UpdateManualAlbumArtAsync(artist, album, path);
// Update the icon in our list
quint64 id = cover_loader_->Worker()->LoadImageAsync(QString(), path);
item->setData(Role_PathManual, path);
cover_loading_tasks_[id] = item;
}
void AlbumCoverManager::UpdateStatusText() {
QString message = tr("Got %1 covers out of %2 (%3 failed)")
.arg(got_covers_).arg(jobs_).arg(missing_covers_);
@ -554,3 +564,22 @@ void AlbumCoverManager::LoadSelectedToPlaylist() {
emit LoadSongsToPlaylist(GetSongsInAlbums(
ui_->albums->selectionModel()->selectedIndexes()));
}
void AlbumCoverManager::SearchManual() {
if (context_menu_items_.isEmpty())
return;
// Get something sensible to stick in the search box
QString query = context_menu_items_[0]->data(Role_ArtistName).toString();
if (!query.isEmpty())
query += " ";
query += context_menu_items_[0]->data(Role_AlbumName).toString();
QImage image = cover_searcher_->Exec(query);
if (image.isNull())
return;
foreach (QListWidgetItem* item, context_menu_items_) {
SaveAndSetCover(item, image);
}
}

View File

@ -29,6 +29,7 @@
class LibraryBackend;
class AlbumCoverFetcher;
class AlbumCoverSearcher;
class NetworkAccessManager;
class Ui_CoverManager;
@ -46,6 +47,7 @@ class AlbumCoverManager : public QMainWindow {
static const char* kSettingsGroup;
LibraryBackend* backend() const { return backend_; }
QIcon no_cover_icon() const { return no_cover_icon_; }
void Reset();
void Init();
@ -77,6 +79,7 @@ class AlbumCoverManager : public QMainWindow {
// On the context menu
void ShowFullsize();
void FetchSingleCover();
void SearchManual();
void ChooseManualCover();
void UnsetCover();
@ -109,6 +112,7 @@ class AlbumCoverManager : public QMainWindow {
void UpdateStatusText();
bool ShouldHide(const QListWidgetItem& item, const QString& filter, HideCovers hide) const;
void SaveAndSetCover(QListWidgetItem* item, const QImage& image);
private:
bool constructed_;
@ -127,6 +131,8 @@ class AlbumCoverManager : public QMainWindow {
AlbumCoverFetcher* cover_fetcher_;
QMap<quint64, QListWidgetItem*> cover_fetching_tasks_;
AlbumCoverSearcher* cover_searcher_;
QIcon artist_icon_;
QIcon all_artists_icon_;
QIcon no_cover_icon_;

View File

@ -176,7 +176,7 @@
</action>
<action name="action_choose_manual">
<property name="text">
<string>Choose manual cover...</string>
<string>Load cover from disk...</string>
</property>
</action>
<action name="action_unset_cover">
@ -194,6 +194,11 @@
<string>Add to playlist</string>
</property>
</action>
<action name="action_search_manual">
<property name="text">
<string>Search for album covers...</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -0,0 +1,134 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "albumcovermanager.h"
#include "albumcoversearcher.h"
#include "ui_albumcoversearcher.h"
#include "core/albumcoverfetcher.h"
#include "core/albumcoverloader.h"
#include <QKeyEvent>
#include <QListWidgetItem>
AlbumCoverSearcher::AlbumCoverSearcher(AlbumCoverManager* parent)
: QDialog(parent),
ui_(new Ui_AlbumCoverSearcher),
manager_(parent),
fetcher_(NULL),
id_(0)
{
ui_->setupUi(this);
ui_->busy->hide();
connect(ui_->search, SIGNAL(clicked()), SLOT(Search()));
connect(ui_->covers, SIGNAL(doubleClicked(QModelIndex)), SLOT(CoverDoubleClicked(QModelIndex)));
}
AlbumCoverSearcher::~AlbumCoverSearcher() {
delete ui_;
}
void AlbumCoverSearcher::Init(boost::shared_ptr<AlbumCoverLoader> loader,
AlbumCoverFetcher *fetcher) {
loader_ = loader;
fetcher_ = fetcher;
connect(fetcher_, SIGNAL(SearchFinished(quint64,AlbumCoverFetcher::SearchResults)), SLOT(SearchFinished(quint64,AlbumCoverFetcher::SearchResults)));
connect(loader_.get(), SIGNAL(ImageLoaded(quint64,QImage)), SLOT(ImageLoaded(quint64,QImage)));
}
QImage AlbumCoverSearcher::Exec(const QString &query) {
ui_->query->setText(query);
ui_->query->setFocus();
Search();
if (exec() == QDialog::Rejected)
return QImage();
if (!ui_->covers->currentItem())
return QImage();
QIcon icon = ui_->covers->currentItem()->icon();
if (icon.cacheKey() == manager_->no_cover_icon().cacheKey())
return QImage();
return icon.pixmap(icon.availableSizes()[0]).toImage();
}
void AlbumCoverSearcher::Search() {
ui_->busy->show();
ui_->search->setEnabled(false);
ui_->query->setEnabled(false);
ui_->covers->setEnabled(false);
id_ = fetcher_->SearchForCovers(ui_->query->text());
}
void AlbumCoverSearcher::SearchFinished(quint64 id, const AlbumCoverFetcher::SearchResults &results) {
if (id != id_)
return;
ui_->search->setEnabled(true);
ui_->query->setEnabled(true);
ui_->covers->setEnabled(true);
id_ = 0;
ui_->covers->clear();
cover_loading_tasks_.clear();
foreach (const AlbumCoverFetcher::SearchResult& result, results) {
if (result.image_url.isEmpty())
continue;
quint64 id = loader_->LoadImageAsync(result.image_url, QString());
QListWidgetItem* item = new QListWidgetItem(ui_->covers);
item->setIcon(manager_->no_cover_icon());
item->setText(result.artist + " - " + result.album);
item->setData(Role_ImageURL, result.image_url);
item->setData(Role_ImageRequestId, id);
item->setData(Qt::TextAlignmentRole, QVariant(Qt::AlignTop | Qt::AlignHCenter));
cover_loading_tasks_[id] = item;
}
if (cover_loading_tasks_.isEmpty())
ui_->busy->hide();
}
void AlbumCoverSearcher::ImageLoaded(quint64 id, const QImage &image) {
if (!cover_loading_tasks_.contains(id))
return;
QListWidgetItem* item = cover_loading_tasks_.take(id);
item->setIcon(QIcon(QPixmap::fromImage(image)));
if (cover_loading_tasks_.isEmpty())
ui_->busy->hide();
}
void AlbumCoverSearcher::keyPressEvent(QKeyEvent* e) {
if (e->key() == Qt::Key_Enter ||
e->key() == Qt::Key_Return) {
e->ignore();
return;
}
QDialog::keyPressEvent(e);
}
void AlbumCoverSearcher::CoverDoubleClicked(const QModelIndex &index) {
if (index.isValid())
accept();
}

View File

@ -0,0 +1,71 @@
/* This file is part of Clementine.
Clementine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ALBUMCOVERSEARCHER_H
#define ALBUMCOVERSEARCHER_H
#include "core/albumcoverfetcher.h"
#include <QDialog>
#include <boost/shared_ptr.hpp>
class AlbumCoverLoader;
class AlbumCoverManager;
class Ui_AlbumCoverSearcher;
class QListWidgetItem;
class QModelIndex;
class AlbumCoverSearcher : public QDialog {
Q_OBJECT
public:
AlbumCoverSearcher(AlbumCoverManager* parent);
~AlbumCoverSearcher();
enum Role {
Role_ImageURL = Qt::UserRole + 1,
Role_ImageRequestId,
};
void Init(boost::shared_ptr<AlbumCoverLoader> loader,
AlbumCoverFetcher* fetcher);
QImage Exec(const QString& query);
protected:
void keyPressEvent(QKeyEvent *);
private slots:
void Search();
void SearchFinished(quint64 id, const AlbumCoverFetcher::SearchResults& results);
void ImageLoaded(quint64 id, const QImage& image);
void CoverDoubleClicked(const QModelIndex& index);
private:
Ui_AlbumCoverSearcher* ui_;
AlbumCoverManager* manager_;
boost::shared_ptr<AlbumCoverLoader> loader_;
AlbumCoverFetcher* fetcher_;
quint64 id_;
QMap<quint64, QListWidgetItem*> cover_loading_tasks_;
};
#endif // ALBUMCOVERSEARCHER_H

View File

@ -0,0 +1,150 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AlbumCoverSearcher</class>
<widget class="QDialog" name="AlbumCoverSearcher">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>624</width>
<height>330</height>
</rect>
</property>
<property name="windowTitle">
<string>Cover Manager</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="LineEdit" name="query">
<property name="hint" stdset="0">
<string>Enter search terms here</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="search">
<property name="text">
<string>Search</string>
</property>
</widget>
</item>
<item>
<widget class="BusyIndicator" name="busy"/>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="covers">
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="iconSize">
<size>
<width>120</width>
<height>120</height>
</size>
</property>
<property name="movement">
<enum>QListView::Static</enum>
</property>
<property name="flow">
<enum>QListView::TopToBottom</enum>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="spacing">
<number>2</number>
</property>
<property name="viewMode">
<enum>QListView::IconMode</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>LineEdit</class>
<extends>QLineEdit</extends>
<header>widgets/lineedit.h</header>
</customwidget>
<customwidget>
<class>BusyIndicator</class>
<extends>QLabel</extends>
<header>widgets/busyindicator.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>query</tabstop>
<tabstop>search</tabstop>
<tabstop>covers</tabstop>
<tabstop>buttonBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AlbumCoverSearcher</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AlbumCoverSearcher</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>query</sender>
<signal>returnPressed()</signal>
<receiver>search</receiver>
<slot>click()</slot>
<hints>
<hint type="sourcelabel">
<x>347</x>
<y>50</y>
</hint>
<hint type="destinationlabel">
<x>575</x>
<y>50</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -19,6 +19,7 @@
#include <QLineEdit>
// Remove in Qt 4.7: QLineEdit has placeholderText
class LineEdit : public QLineEdit {
Q_OBJECT
Q_PROPERTY(QString hint READ GetHint WRITE SetHint);