diff --git a/devices/mtpdevice.cpp b/devices/mtpdevice.cpp index 2737f542e..f6041578f 100644 --- a/devices/mtpdevice.cpp +++ b/devices/mtpdevice.cpp @@ -637,7 +637,7 @@ void MtpConnection::putSong(const Song &s, bool fixVa, const DeviceOptions &opts } if (album) { - Covers::Image image=Covers::getImage(s); + Covers::Image image=Covers::self()->getImage(s); if (!image.img.isNull()) { // First check if album already has cover... if (!albumsWithCovers.contains(album) && getCover(album).isNull()) { diff --git a/gui/coverdialog.cpp b/gui/coverdialog.cpp index 0448ffb9d..1124665dd 100644 --- a/gui/coverdialog.cpp +++ b/gui/coverdialog.cpp @@ -400,7 +400,7 @@ CoverDialog::~CoverDialog() void CoverDialog::show(const Song &s) { song=s; - Covers::Image img=Covers::getImage(song); + Covers::Image img=Covers::self()->getImage(song); if (!img.fileName.isEmpty() && !QFileInfo(img.fileName).isWritable()) { MessageBox::error(parentWidget(), i18n("

A cover already exists for this album, and the file is not writeable.

%1

").arg(img.fileName)); diff --git a/gui/covers.cpp b/gui/covers.cpp index 88f4cb4ca..e9b5778ce 100644 --- a/gui/covers.cpp +++ b/gui/covers.cpp @@ -135,6 +135,16 @@ static QString save(const QString &mimeType, const QString &extension, const QSt return QString(); } +static inline QString albumKey(const Song &s) +{ + return "{"+s.albumArtist()+"}{"+s.album+"}"; +} + +static inline QString artistKey(const Song &s) +{ + return "{"+s.albumArtist()+"}"; +} + QString Covers::encodeName(QString name) { name.replace("/", "_"); @@ -171,36 +181,30 @@ static QString kdeHome() } #endif -struct AppCover -{ - QImage img; - QString filename; -}; - -static AppCover otherAppCover(const Covers::Job &job) +static Covers::Image otherAppCover(const Covers::Job &job) { #ifdef ENABLE_KDE_SUPPORT QString kdeDir=KGlobal::dirs()->localkdedir(); #else QString kdeDir=kdeHome(); #endif - AppCover app; - app.filename=kdeDir+QLatin1String("/share/apps/amarok/albumcovers/large/")+ + Covers::Image app; + app.fileName=kdeDir+QLatin1String("/share/apps/amarok/albumcovers/large/")+ QCryptographicHash::hash(job.song.albumArtist().toLower().toLocal8Bit()+job.song.album.toLower().toLocal8Bit(), QCryptographicHash::Md5).toHex(); - app.img=QImage(app.filename); + app.img=QImage(app.fileName); if (app.img.isNull()) { - app.filename=xdgConfig()+QLatin1String("/Clementine/albumcovers/")+ + app.fileName=xdgConfig()+QLatin1String("/Clementine/albumcovers/")+ QCryptographicHash::hash(job.song.albumArtist().toLower().toUtf8()+job.song.album.toLower().toUtf8(), QCryptographicHash::Sha1).toHex()+QLatin1String(".jpg"); - app.img=QImage(app.filename); + app.img=QImage(app.fileName); } if (!app.img.isNull() && saveInMpdDir && canSaveTo(job.dir)) { - QFile f(app.filename); + QFile f(app.fileName); if (f.open(QIODevice::ReadOnly)) { QByteArray raw=f.readAll(); if (!raw.isEmpty()) { @@ -212,7 +216,7 @@ static AppCover otherAppCover(const Covers::Job &job) } savedName=save(mimeType, mimeType.isEmpty() ? constExtensions.at(0) : mimeType, job.dir+coverName, app.img, raw); if (!savedName.isEmpty()) { - app.filename=savedName; + app.fileName=savedName; } } } @@ -358,8 +362,6 @@ static inline QString cacheKey(const Song &song, int size) return song.albumArtist()+QChar(':')+song.album+QChar(':')+QChar(':')+QString::number(size); } -static QSet cacheSizes; - QPixmap * Covers::get(const Song &song, int size) { if (song.isUnknown()) { @@ -424,8 +426,18 @@ void Covers::clearCache(const Song &song, const QImage &img, bool dummyEntriesOn Covers::Image Covers::getImage(const Song &song) { - QString songFile=song.file; bool isArtistImage=isRequestingArtistImage(song); + QString prevFileName=getFilename(song, isArtistImage); + + if (!prevFileName.isEmpty()) { + QImage img(prevFileName); + + if (!img.isNull()) { + return Image(img, prevFileName); + } + } + + QString songFile=song.file; QString dirName; bool haveAbsPath=song.file.startsWith('/'); @@ -433,7 +445,7 @@ Covers::Image Covers::getImage(const Song &song) QUrl u(songFile); songFile=u.hasQueryItem("file") ? u.queryItemValue("file") : QString(); } - if (!songFile.isEmpty() && ! song.file.startsWith(("http:/")) && + if (!songFile.isEmpty() && !song.file.startsWith(("http:/")) && (haveAbsPath || (!MPDConnection::self()->getDetails().dir.isEmpty() && !MPDConnection::self()->getDetails().dir.startsWith(QLatin1String("http://")) ) ) ) { dirName=songFile.endsWith('/') ? (haveAbsPath ? QString() : MPDConnection::self()->getDetails().dir)+songFile : Utils::getDir((haveAbsPath ? QString() : MPDConnection::self()->getDetails().dir)+songFile); @@ -445,7 +457,9 @@ Covers::Image Covers::getImage(const Song &song) QImage img(dirName+fileName); if (!img.isNull()) { - return Image(img, dirName+fileName); + Image i(img, dirName+fileName); + gotArtistImage(song, i, false); + return i; } } } @@ -477,7 +491,9 @@ Covers::Image Covers::getImage(const Song &song) QImage img(dirName+fileName); if (!img.isNull()) { - return Image(img, dirName+fileName); + Image i(img, dirName+fileName); + gotAlbumCover(song, i, false); + return i; } } } @@ -497,7 +513,9 @@ Covers::Image Covers::getImage(const Song &song) QImage img(dirName+fileName); if (!img.isNull()) { - return Image(img, dirName+fileName); + Image i(img, dirName+fileName); + gotAlbumCover(song, i, false); + return i; } } } @@ -511,7 +529,9 @@ Covers::Image Covers::getImage(const Song &song) if (QFile::exists(dir+artist+ext)) { QImage img(dir+artist+ext); if (!img.isNull()) { - return Image(img, dir+artist+ext); + Image i(img, dir+artist+ext); + gotArtistImage(song, i, false); + return i; } } } @@ -523,7 +543,9 @@ Covers::Image Covers::getImage(const Song &song) if (QFile::exists(dir+album+ext)) { QImage img(dir+album+ext); if (!img.isNull()) { - return Image(img, dir+album+ext); + Image i(img, dir+album+ext); + gotAlbumCover(song, i, false); + return i; } } } @@ -532,9 +554,10 @@ Covers::Image Covers::getImage(const Song &song) #if !defined Q_OS_WIN // See if amarok, or clementine, has it... - AppCover app=otherAppCover(job); + Image app=otherAppCover(job); if (!app.img.isNull()) { - return Image(app.img, app.filename); + gotAlbumCover(song, app, false); + return app; } #endif } @@ -817,8 +840,7 @@ void Covers::lastFmCallFinished() #if defined Q_OS_WIN emit cover(job.song, QImage(), QString()); #else - AppCover app=otherAppCover(job); - emit cover(job.song, app.img, app.filename); + gotAlbumCover(job.song, otherAppCover(job)); #endif } } @@ -839,41 +861,40 @@ void Covers::jobFinished() if (it!=end) { QByteArray data=QNetworkReply::NoError==reply->error() ? reply->readAll() : QByteArray(); QString url=reply->url().toString(); - QImage img = data.isEmpty() ? QImage() : QImage::fromData(data, url.endsWith(".jpg") ? "JPG" : (url.endsWith(".png") ? "PNG" : 0)); - QString fileName; + Image img; + img.img= data.isEmpty() ? QImage() : QImage::fromData(data, url.endsWith(".jpg") ? "JPG" : (url.endsWith(".png") ? "PNG" : 0)); Job job=it.value(); - if (!img.isNull() && img.size().width()<32) { - img = QImage(); + if (!img.img.isNull() && img.img.size().width()<32) { + img.img = QImage(); } jobs.remove(it.key()); - if (img.isNull() && JobLastFm!=job.type && JobOnline) { + if (img.img.isNull() && JobLastFm!=job.type && JobOnline) { if (JobHttpJpg==job.type) { downloadViaHttp(job, JobHttpPng); } else { downloadViaLastFm(job); } } else { - if (!img.isNull()) { - if (img.size().width()>constMaxSize.width() || img.size().height()>constMaxSize.height()) { - img=img.scaled(constMaxSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); + if (!img.img.isNull()) { + if (img.img.size().width()>constMaxSize.width() || img.img.size().height()>constMaxSize.height()) { + img.img=img.img.scaled(constMaxSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); } - fileName=saveImg(job, img, data); - clearCache(job.song, img, true); + img.fileName=saveImg(job, img.img, data); + clearCache(job.song, img.img, true); } if (job.isArtist) { - emit artistImage(job.song, img); - } else if (img.isNull()) { + gotArtistImage(job.song, img); + } else if (img.img.isNull()) { #if defined Q_OS_WIN emit cover(job.song, QImage(), QString()); #else - AppCover app=otherAppCover(job); - emit cover(job.song, app.img, app.filename); + gotAlbumCover(job.song, otherAppCover(job)); #endif } else { - emit cover(job.song, img, fileName); + gotAlbumCover(job.song, img); } } } @@ -952,3 +973,29 @@ QHash::Iterator Covers::findJob(const Job &job) return end; } + +void Covers::gotAlbumCover(const Song &song, const Image &img, bool emitResult) +{ + if (!img.img.isNull() && !img.fileName.isEmpty() && !img.fileName.startsWith("http:/")) { + filenames.insert(albumKey(song), img.fileName); + } + if (emitResult) { + emit cover(song, img.img, img.fileName); + } +} + +void Covers::gotArtistImage(const Song &song, const Image &img, bool emitResult) +{ + if (!img.img.isNull() && !img.fileName.isEmpty() && !img.fileName.startsWith("http:/")) { + filenames.insert(artistKey(song), img.fileName); + } + if (emitResult) { + emit artistImage(song, img.img); + } +} + +QString Covers::getFilename(const Song &s, bool isArtist) +{ + QMap::ConstIterator fileIt=filenames.find(isArtist ? artistKey(s) : albumKey(s)); + return fileIt==filenames.end() ? QString() : fileIt.value(); +} diff --git a/gui/covers.h b/gui/covers.h index 4058e5865..b2da470b5 100644 --- a/gui/covers.h +++ b/gui/covers.h @@ -26,6 +26,8 @@ #include #include +#include +#include #include #include #include @@ -91,7 +93,7 @@ public: struct Image { - Image(const QImage &i, const QString &f) + Image(const QImage &i=QImage(), const QString &f=QString()) : img(i) , fileName(f) { } @@ -115,7 +117,7 @@ public: void stop(); QPixmap * get(const Song &song, int size); - static Image getImage(const Song &song); + Image getImage(const Song &song); Image get(const Song &song); void requestCover(const Song &song, bool urgent=false); void setSaveInMpdDir(bool s); @@ -143,10 +145,15 @@ private: QString saveImg(const Job &job, const QImage &img, const QByteArray &raw); QHash::Iterator findJob(const Job &job); void clearCache(const Song &song, const QImage &img, bool dummyEntriesOnly); + void gotAlbumCover(const Song &song, const Image &img, bool emitResult=true); + void gotArtistImage(const Song &song, const Image &img, bool emitResult=true); + QString getFilename(const Song &s, bool isArtist); private: QHash jobs; + QSet cacheSizes; QCache cache; + QMap filenames; CoverQueue *queue; QThread *queueThread; };