Fetch missing album covers from last.fm :)
This commit is contained in:
parent
eb3b286f0d
commit
605e3a87cc
@ -1,39 +1,80 @@
|
|||||||
#include "albumcoverfetcher.h"
|
#include "albumcoverfetcher.h"
|
||||||
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#include <lastfm/Artist>
|
#include <lastfm/Artist>
|
||||||
#include <lastfm/XmlQuery>
|
#include <lastfm/XmlQuery>
|
||||||
#include <lastfm/ws.h>
|
#include <lastfm/ws.h>
|
||||||
|
|
||||||
|
const int AlbumCoverFetcher::kMaxConcurrentRequests = 5;
|
||||||
|
|
||||||
AlbumCoverFetcher::AlbumCoverFetcher(QObject* parent)
|
AlbumCoverFetcher::AlbumCoverFetcher(QObject* parent)
|
||||||
: QObject(parent) {
|
: QObject(parent),
|
||||||
|
next_id_(0),
|
||||||
|
request_starter_(new QTimer(this))
|
||||||
|
{
|
||||||
|
request_starter_->setInterval(1000);
|
||||||
|
connect(request_starter_, SIGNAL(timeout()), SLOT(StartRequests()));
|
||||||
}
|
}
|
||||||
|
|
||||||
lastfm::Album AlbumCoverFetcher::FetchAlbumCover(
|
quint64 AlbumCoverFetcher::FetchAlbumCover(
|
||||||
const QString& artist_name, const QString& album_name) {
|
const QString& artist_name, const QString& album_name) {
|
||||||
lastfm::Artist artist(artist_name);
|
QueuedRequest request;
|
||||||
lastfm::Album album(artist, album_name);
|
request.album = album_name;
|
||||||
|
request.artist = artist_name;
|
||||||
|
request.id = next_id_ ++;
|
||||||
|
|
||||||
QNetworkReply* reply = album.getInfo();
|
queued_requests_.enqueue(request);
|
||||||
connect(reply, SIGNAL(finished()), SLOT(AlbumGetInfoFinished()));
|
|
||||||
requests_.insert(reply, album);
|
if (!request_starter_->isActive())
|
||||||
return album;
|
request_starter_->start();
|
||||||
|
|
||||||
|
if (active_requests_.count() < kMaxConcurrentRequests)
|
||||||
|
StartRequests();
|
||||||
|
|
||||||
|
return request.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlbumCoverFetcher::Clear() {
|
||||||
|
queued_requests_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlbumCoverFetcher::StartRequests() {
|
||||||
|
if (queued_requests_.isEmpty()) {
|
||||||
|
request_starter_->stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!queued_requests_.isEmpty() &&
|
||||||
|
active_requests_.count() < kMaxConcurrentRequests) {
|
||||||
|
QueuedRequest request = queued_requests_.dequeue();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlbumCoverFetcher::AlbumGetInfoFinished() {
|
void AlbumCoverFetcher::AlbumGetInfoFinished() {
|
||||||
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
quint64 id = active_requests_.take(reply);
|
||||||
|
|
||||||
lastfm::XmlQuery query(lastfm::ws::parse(reply));
|
try {
|
||||||
qDebug() << query["album"]["image size=large"].text();
|
lastfm::XmlQuery query(lastfm::ws::parse(reply));
|
||||||
|
|
||||||
QUrl image_url(query["album"]["image size=large"].text());
|
QUrl image_url(query["album"]["image size=large"].text());
|
||||||
QNetworkReply* image_reply = network_.get(QNetworkRequest(image_url));
|
QNetworkReply* image_reply = network_.get(QNetworkRequest(image_url));
|
||||||
connect(image_reply, SIGNAL(finished()), SLOT(AlbumCoverFetchFinished()));
|
connect(image_reply, SIGNAL(finished()), SLOT(AlbumCoverFetchFinished()));
|
||||||
|
|
||||||
lastfm::Album album = requests_.take(reply);
|
active_requests_[image_reply] = id;
|
||||||
requests_[image_reply] = album;
|
} catch (std::runtime_error&) {
|
||||||
|
emit AlbumCoverFetched(id, QImage());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlbumCoverFetcher::AlbumCoverFetchFinished() {
|
void AlbumCoverFetcher::AlbumCoverFetchFinished() {
|
||||||
@ -43,6 +84,6 @@ void AlbumCoverFetcher::AlbumCoverFetchFinished() {
|
|||||||
QImage image;
|
QImage image;
|
||||||
image.loadFromData(reply->readAll());
|
image.loadFromData(reply->readAll());
|
||||||
|
|
||||||
lastfm::Album album = requests_.take(reply);
|
quint64 id = active_requests_.take(reply);
|
||||||
emit AlbumCoverFetched(album, image);
|
emit AlbumCoverFetched(id, image);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QNetworkAccessManager>
|
#include <QNetworkAccessManager>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QQueue>
|
||||||
|
|
||||||
#include <lastfm/Album>
|
#include <lastfm/Album>
|
||||||
|
|
||||||
@ -18,18 +19,34 @@ class AlbumCoverFetcher : public QObject {
|
|||||||
AlbumCoverFetcher(QObject* parent = 0);
|
AlbumCoverFetcher(QObject* parent = 0);
|
||||||
virtual ~AlbumCoverFetcher() {}
|
virtual ~AlbumCoverFetcher() {}
|
||||||
|
|
||||||
lastfm::Album FetchAlbumCover(const QString& artist, const QString& album);
|
static const int kMaxConcurrentRequests;
|
||||||
|
|
||||||
|
quint64 FetchAlbumCover(const QString& artist, const QString& album);
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void AlbumCoverFetched(const lastfm::Album&, const QImage& cover);
|
void AlbumCoverFetched(quint64, const QImage& cover);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void AlbumGetInfoFinished();
|
void AlbumGetInfoFinished();
|
||||||
void AlbumCoverFetchFinished();
|
void AlbumCoverFetchFinished();
|
||||||
|
void StartRequests();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct QueuedRequest {
|
||||||
|
quint64 id;
|
||||||
|
QString artist;
|
||||||
|
QString album;
|
||||||
|
};
|
||||||
|
|
||||||
QNetworkAccessManager network_;
|
QNetworkAccessManager network_;
|
||||||
QMap<QNetworkReply*, lastfm::Album> requests_;
|
quint64 next_id_;
|
||||||
|
|
||||||
|
QQueue<QueuedRequest> queued_requests_;
|
||||||
|
QMap<QNetworkReply*, quint64> active_requests_;
|
||||||
|
|
||||||
|
QTimer* request_starter_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ALBUMCOVERFETCHER_H
|
#endif // ALBUMCOVERFETCHER_H
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#include "albumcoverloader.h"
|
#include "albumcoverloader.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
AlbumCoverLoader::AlbumCoverLoader(QObject* parent)
|
AlbumCoverLoader::AlbumCoverLoader(QObject* parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
@ -9,6 +11,11 @@ AlbumCoverLoader::AlbumCoverLoader(QObject* parent)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString AlbumCoverLoader::ImageCacheDir() {
|
||||||
|
return QString("%1/.config/%2/albumcovers/")
|
||||||
|
.arg(QDir::homePath(), QCoreApplication::organizationName());
|
||||||
|
}
|
||||||
|
|
||||||
void AlbumCoverLoader::Clear() {
|
void AlbumCoverLoader::Clear() {
|
||||||
QMutexLocker l(&mutex_);
|
QMutexLocker l(&mutex_);
|
||||||
tasks_.clear();
|
tasks_.clear();
|
||||||
|
@ -14,6 +14,8 @@ class AlbumCoverLoader : public QObject {
|
|||||||
public:
|
public:
|
||||||
AlbumCoverLoader(QObject* parent = 0);
|
AlbumCoverLoader(QObject* parent = 0);
|
||||||
|
|
||||||
|
static QString ImageCacheDir();
|
||||||
|
|
||||||
void SetDesiredHeight(int height) { height_ = height; }
|
void SetDesiredHeight(int height) { height_ = height; }
|
||||||
quint64 LoadImageAsync(const QString& art_automatic, const QString& art_manual);
|
quint64 LoadImageAsync(const QString& art_automatic, const QString& art_manual);
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "albumcovermanager.h"
|
#include "albumcovermanager.h"
|
||||||
|
#include "albumcoverfetcher.h"
|
||||||
#include "librarybackend.h"
|
#include "librarybackend.h"
|
||||||
#include "libraryquery.h"
|
#include "libraryquery.h"
|
||||||
|
|
||||||
@ -6,12 +7,16 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QActionGroup>
|
#include <QActionGroup>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QCryptographicHash>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
const char* AlbumCoverManager::kSettingsGroup = "CoverManager";
|
const char* AlbumCoverManager::kSettingsGroup = "CoverManager";
|
||||||
|
|
||||||
AlbumCoverManager::AlbumCoverManager(QWidget *parent)
|
AlbumCoverManager::AlbumCoverManager(QWidget *parent)
|
||||||
: QDialog(parent),
|
: QDialog(parent),
|
||||||
cover_loader_(new BackgroundThread<AlbumCoverLoader>(this)),
|
cover_loader_(new BackgroundThread<AlbumCoverLoader>(this)),
|
||||||
|
cover_fetcher_(new AlbumCoverFetcher(this)),
|
||||||
artist_icon_(":/artist.png"),
|
artist_icon_(":/artist.png"),
|
||||||
all_artists_icon_(":/album.png")
|
all_artists_icon_(":/album.png")
|
||||||
{
|
{
|
||||||
@ -50,6 +55,9 @@ AlbumCoverManager::AlbumCoverManager(QWidget *parent)
|
|||||||
connect(ui_.filter, SIGNAL(textChanged(QString)), SLOT(UpdateFilter()));
|
connect(ui_.filter, SIGNAL(textChanged(QString)), SLOT(UpdateFilter()));
|
||||||
connect(filter_group, SIGNAL(triggered(QAction*)), SLOT(UpdateFilter()));
|
connect(filter_group, SIGNAL(triggered(QAction*)), SLOT(UpdateFilter()));
|
||||||
connect(ui_.view, SIGNAL(clicked()), ui_.view, SLOT(showMenu()));
|
connect(ui_.view, SIGNAL(clicked()), ui_.view, SLOT(showMenu()));
|
||||||
|
connect(ui_.fetch, SIGNAL(clicked()), SLOT(FetchAlbumCovers()));
|
||||||
|
connect(cover_fetcher_, SIGNAL(AlbumCoverFetched(quint64,QImage)),
|
||||||
|
SLOT(AlbumCoverFetched(quint64,QImage)));
|
||||||
|
|
||||||
// Restore settings
|
// Restore settings
|
||||||
QSettings s;
|
QSettings s;
|
||||||
@ -64,6 +72,10 @@ AlbumCoverManager::AlbumCoverManager(QWidget *parent)
|
|||||||
cover_loader_->start();
|
cover_loader_->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AlbumCoverManager::~AlbumCoverManager() {
|
||||||
|
CancelRequests();
|
||||||
|
}
|
||||||
|
|
||||||
void AlbumCoverManager::CoverLoaderInitialised() {
|
void AlbumCoverManager::CoverLoaderInitialised() {
|
||||||
connect(cover_loader_->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage)),
|
connect(cover_loader_->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage)),
|
||||||
SLOT(CoverImageLoaded(quint64,QImage)));
|
SLOT(CoverImageLoaded(quint64,QImage)));
|
||||||
@ -81,11 +93,24 @@ void AlbumCoverManager::showEvent(QShowEvent *) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AlbumCoverManager::closeEvent(QCloseEvent *) {
|
void AlbumCoverManager::closeEvent(QCloseEvent *) {
|
||||||
|
// Save geometry
|
||||||
QSettings s;
|
QSettings s;
|
||||||
s.beginGroup(kSettingsGroup);
|
s.beginGroup(kSettingsGroup);
|
||||||
|
|
||||||
s.setValue("geometry", saveGeometry());
|
s.setValue("geometry", saveGeometry());
|
||||||
s.setValue("splitter_state", ui_.splitter->saveState());
|
s.setValue("splitter_state", ui_.splitter->saveState());
|
||||||
|
|
||||||
|
// Cancel any outstanding requests
|
||||||
|
CancelRequests();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlbumCoverManager::CancelRequests() {
|
||||||
|
cover_loading_tasks_.clear();
|
||||||
|
cover_loader_->Worker()->Clear();
|
||||||
|
|
||||||
|
cover_fetching_tasks_.clear();
|
||||||
|
cover_fetcher_->Clear();
|
||||||
|
ui_.fetch->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AlbumCoverManager::Reset() {
|
void AlbumCoverManager::Reset() {
|
||||||
@ -114,11 +139,12 @@ void AlbumCoverManager::ArtistChanged(QListWidgetItem* current) {
|
|||||||
artist = current->text();
|
artist = current->text();
|
||||||
|
|
||||||
ui_.albums->clear();
|
ui_.albums->clear();
|
||||||
cover_loading_tasks_.clear();
|
CancelRequests();
|
||||||
cover_loader_->Worker()->Clear();
|
|
||||||
|
|
||||||
foreach (const LibraryBackend::AlbumArtInfo& info, backend_->GetAlbumArtInfo(artist)) {
|
foreach (const LibraryBackend::AlbumArtInfo& info, backend_->GetAlbumArtInfo(artist)) {
|
||||||
QListWidgetItem* item = new QListWidgetItem(no_cover_icon_, info.album_name, ui_.albums);
|
QListWidgetItem* item = new QListWidgetItem(no_cover_icon_, info.album_name, ui_.albums);
|
||||||
|
item->setData(Role_ArtistName, info.artist);
|
||||||
|
item->setData(Role_AlbumName, info.album_name);
|
||||||
|
|
||||||
if (!info.art_automatic.isEmpty() || !info.art_manual.isEmpty()) {
|
if (!info.art_automatic.isEmpty() || !info.art_manual.isEmpty()) {
|
||||||
quint64 id = cover_loader_->Worker()->LoadImageAsync(
|
quint64 id = cover_loader_->Worker()->LoadImageAsync(
|
||||||
@ -158,3 +184,56 @@ void AlbumCoverManager::UpdateFilter() {
|
|||||||
(!has_cover && hide_without_covers));
|
(!has_cover && hide_without_covers));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AlbumCoverManager::FetchAlbumCovers() {
|
||||||
|
for (int i=0 ; i<ui_.albums->count() ; ++i) {
|
||||||
|
QListWidgetItem* item = ui_.albums->item(i);
|
||||||
|
if (item->isHidden())
|
||||||
|
continue;
|
||||||
|
if (item->icon().cacheKey() != no_cover_icon_.cacheKey())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
quint64 id = cover_fetcher_->FetchAlbumCover(
|
||||||
|
item->data(Role_ArtistName).toString(), item->data(Role_AlbumName).toString());
|
||||||
|
cover_fetching_tasks_[id] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cover_fetching_tasks_.isEmpty())
|
||||||
|
ui_.fetch->setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AlbumCoverManager::AlbumCoverFetched(quint64 id, const QImage &image) {
|
||||||
|
if (!cover_fetching_tasks_.contains(id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
QListWidgetItem* item = cover_fetching_tasks_.take(id);
|
||||||
|
if (!image.isNull()) {
|
||||||
|
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);
|
||||||
|
cover_loading_tasks_[id] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cover_fetching_tasks_.isEmpty())
|
||||||
|
ui_.fetch->setEnabled(true);
|
||||||
|
}
|
||||||
|
@ -11,11 +11,13 @@
|
|||||||
#include "albumcoverloader.h"
|
#include "albumcoverloader.h"
|
||||||
|
|
||||||
class LibraryBackend;
|
class LibraryBackend;
|
||||||
|
class AlbumCoverFetcher;
|
||||||
|
|
||||||
class AlbumCoverManager : public QDialog {
|
class AlbumCoverManager : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
AlbumCoverManager(QWidget *parent = 0);
|
AlbumCoverManager(QWidget *parent = 0);
|
||||||
|
~AlbumCoverManager();
|
||||||
|
|
||||||
static const char* kSettingsGroup;
|
static const char* kSettingsGroup;
|
||||||
|
|
||||||
@ -33,6 +35,8 @@ class AlbumCoverManager : public QDialog {
|
|||||||
void CoverLoaderInitialised();
|
void CoverLoaderInitialised();
|
||||||
void CoverImageLoaded(quint64 id, const QImage& image);
|
void CoverImageLoaded(quint64 id, const QImage& image);
|
||||||
void UpdateFilter();
|
void UpdateFilter();
|
||||||
|
void FetchAlbumCovers();
|
||||||
|
void AlbumCoverFetched(quint64 id, const QImage& image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum ArtistItemType {
|
enum ArtistItemType {
|
||||||
@ -40,6 +44,13 @@ class AlbumCoverManager : public QDialog {
|
|||||||
Specific_Artist,
|
Specific_Artist,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Role {
|
||||||
|
Role_ArtistName = Qt::UserRole + 1,
|
||||||
|
Role_AlbumName,
|
||||||
|
};
|
||||||
|
|
||||||
|
void CancelRequests();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::CoverManager ui_;
|
Ui::CoverManager ui_;
|
||||||
boost::shared_ptr<LibraryBackend> backend_;
|
boost::shared_ptr<LibraryBackend> backend_;
|
||||||
@ -51,6 +62,9 @@ class AlbumCoverManager : public QDialog {
|
|||||||
BackgroundThread<AlbumCoverLoader>* cover_loader_;
|
BackgroundThread<AlbumCoverLoader>* cover_loader_;
|
||||||
QMap<quint64, QListWidgetItem*> cover_loading_tasks_;
|
QMap<quint64, QListWidgetItem*> cover_loading_tasks_;
|
||||||
|
|
||||||
|
AlbumCoverFetcher* cover_fetcher_;
|
||||||
|
QMap<quint64, QListWidgetItem*> cover_fetching_tasks_;
|
||||||
|
|
||||||
QIcon artist_icon_;
|
QIcon artist_icon_;
|
||||||
QIcon all_artists_icon_;
|
QIcon all_artists_icon_;
|
||||||
QIcon no_cover_icon_;
|
QIcon no_cover_icon_;
|
||||||
|
@ -526,7 +526,7 @@ QList<LibraryBackend::AlbumArtInfo>
|
|||||||
const QueryOptions& opt) {
|
const QueryOptions& opt) {
|
||||||
QList<AlbumArtInfo> ret;
|
QList<AlbumArtInfo> ret;
|
||||||
LibraryQuery query(opt);
|
LibraryQuery query(opt);
|
||||||
query.SetColumnSpec("album, art_automatic, art_manual");
|
query.SetColumnSpec("album, artist, compilation, sampler, art_automatic, art_manual");
|
||||||
query.SetOrderBy("album");
|
query.SetOrderBy("album");
|
||||||
|
|
||||||
if (!artist.isNull())
|
if (!artist.isNull())
|
||||||
@ -541,13 +541,45 @@ QList<LibraryBackend::AlbumArtInfo>
|
|||||||
if (q.value(0).toString() == last_album)
|
if (q.value(0).toString() == last_album)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
bool compilation = q.value(2).toBool() | q.value(3).toBool();
|
||||||
|
|
||||||
AlbumArtInfo info;
|
AlbumArtInfo info;
|
||||||
|
info.artist = compilation ? QString() : q.value(1).toString();
|
||||||
info.album_name = q.value(0).toString();
|
info.album_name = q.value(0).toString();
|
||||||
info.art_automatic = q.value(1).toString();
|
info.art_automatic = q.value(4).toString();
|
||||||
info.art_manual = q.value(2).toString();
|
info.art_manual = q.value(5).toString();
|
||||||
ret << info;
|
ret << info;
|
||||||
|
|
||||||
last_album = info.album_name;
|
last_album = info.album_name;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LibraryBackend::UpdateManualAlbumArtAsync(const QString &artist,
|
||||||
|
const QString &album,
|
||||||
|
const QString &art) {
|
||||||
|
metaObject()->invokeMethod(this, "UpdateManualAlbumArt", Qt::QueuedConnection,
|
||||||
|
Q_ARG(QString, artist),
|
||||||
|
Q_ARG(QString, album),
|
||||||
|
Q_ARG(QString, art));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryBackend::UpdateManualAlbumArt(const QString &artist,
|
||||||
|
const QString &album,
|
||||||
|
const QString &art) {
|
||||||
|
QSqlDatabase db(Connect());
|
||||||
|
|
||||||
|
QString sql("UPDATE songs SET art_manual = :art"
|
||||||
|
" WHERE album = :album");
|
||||||
|
if (!artist.isNull())
|
||||||
|
sql += " AND artist = :artist";
|
||||||
|
|
||||||
|
QSqlQuery q(sql, db);
|
||||||
|
q.bindValue(":art", art);
|
||||||
|
q.bindValue(":album", album);
|
||||||
|
if (!artist.isNull())
|
||||||
|
q.bindValue(":artist", artist);
|
||||||
|
|
||||||
|
q.exec();
|
||||||
|
CheckErrors(q.lastError());
|
||||||
|
}
|
||||||
|
@ -18,6 +18,7 @@ class LibraryBackend : public QObject {
|
|||||||
LibraryBackend(QObject* parent = 0);
|
LibraryBackend(QObject* parent = 0);
|
||||||
|
|
||||||
struct AlbumArtInfo {
|
struct AlbumArtInfo {
|
||||||
|
QString artist;
|
||||||
QString album_name;
|
QString album_name;
|
||||||
QString art_automatic;
|
QString art_automatic;
|
||||||
QString art_manual;
|
QString art_manual;
|
||||||
@ -44,6 +45,7 @@ class LibraryBackend : public QObject {
|
|||||||
SongList GetCompilationSongs(const QString& album, const QueryOptions& opt = QueryOptions());
|
SongList GetCompilationSongs(const QString& album, const QueryOptions& opt = QueryOptions());
|
||||||
|
|
||||||
QList<AlbumArtInfo> GetAlbumArtInfo(const QString& artist = QString(), const QueryOptions& opt = QueryOptions());
|
QList<AlbumArtInfo> GetAlbumArtInfo(const QString& artist = QString(), const QueryOptions& opt = QueryOptions());
|
||||||
|
void UpdateManualAlbumArtAsync(const QString& artist, const QString& album, const QString& art);
|
||||||
|
|
||||||
Song GetSongById(int id);
|
Song GetSongById(int id);
|
||||||
|
|
||||||
@ -71,6 +73,9 @@ class LibraryBackend : public QObject {
|
|||||||
|
|
||||||
void TotalSongCountUpdated(int total);
|
void TotalSongCountUpdated(int total);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void UpdateManualAlbumArt(const QString& artist, const QString& album, const QString& art);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct CompilationInfo {
|
struct CompilationInfo {
|
||||||
CompilationInfo() : has_samplers(false), has_not_samplers(false) {}
|
CompilationInfo() : has_samplers(false), has_not_samplers(false) {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user