diff --git a/README b/README index 9bf586164..636506b3c 100644 --- a/README +++ b/README @@ -355,6 +355,12 @@ maxCoverUpdatePerIteration= displayed. This config controls the number of covers that are sent in one batch. The default is again 5. (Values 1..20 are acceptable) +coverCacheSize= + Cantata stores scaled versions of covers in a cache in memory, to reduce + memory usage and/or disk acicess. This setting controls the maximum size + (in megabytes) that Cantata will use for this cache. The default is 4 + (Values 1..512 are acceptable) + cueFileCodecs= List of extra text codecs to try when loading CUE files. UTF-8 and System default are tried first, and then the entries from this config are tried. @@ -434,6 +440,7 @@ e.g. iconTheme=oxygen maxCoverFindPerIteration=5 maxCoverUpdatePerIteration=5 +coverCacheSize=4 cueFileCodecs=GBK, big5-0 networkAccessEnabled=false volumeStep=2 diff --git a/gui/covers.cpp b/gui/covers.cpp index 5d66bc2ae..b4fcd6a2b 100644 --- a/gui/covers.cpp +++ b/gui/covers.cpp @@ -54,7 +54,6 @@ #include #include #include -#include #ifdef ENABLE_KDE_SUPPORT #include @@ -89,9 +88,6 @@ static bool saveInMpdDir=true; static bool fetchCovers=true; static QString constCoverInTagPrefix=QLatin1String("{tag}"); -static QSet cacheSizes; -static QCache cache(4*1024*1024); - static bool canSaveTo(const QString &dir) { QString mpdDir=MPDConnection::self()->getDetails().dir; @@ -224,52 +220,6 @@ static void clearScaledCache(const Song &song) } } -QPixmap * Covers::getScaledCover(const QString &artist, const QString &album, int size) -{ - if (size<4) { - return 0; - } -// DBUG_CLASS("Covers") << artist << album << size; - QString key=cacheKey(artist, album, size); - QPixmap *pix(cache.object(key)); - if (!pix && cacheScaledCovers) { - QString fileName=getScaledCoverName(artist, album, size, false); - if (!fileName.isEmpty() && QFile::exists(fileName)) { - QImage img(fileName); - if (!img.isNull() && (img.width()==size || img.height()==size)) { - DBUG_CLASS("Covers") << artist << album << size << "scaled cover found" << fileName; - pix=new QPixmap(QPixmap::fromImage(img)); - cache.insert(key, pix, pix->width()*pix->height()*(pix->depth()/8)); - } - } - - if (!pix) { - // Create a dummy pixmap so that we dont keep on stating files that do not exist! - pix=new QPixmap(1, 1); - cache.insert(key, pix, 4); - } - cacheSizes.insert(size); - } - return pix && pix->width()>1 ? pix : 0; -} - -QPixmap * Covers::saveScaledCover(const QImage &img, const QString &artist, const QString &album, int size) -{ - if (size<4) { - return 0; - } - - if (cacheScaledCovers) { - QString fileName=getScaledCoverName(artist, album, size, true); - bool status=img.save(fileName); - DBUG_CLASS("Covers") << artist << album << size << fileName << status; - } - QPixmap *pix=new QPixmap(QPixmap::fromImage(img)); - cache.insert(cacheKey(artist, album, size), pix, pix->width()*pix->height()*(pix->depth()/8)); - cacheSizes.insert(size); - return pix; -} - bool Covers::isJpg(const QByteArray &data) { return data.size()>9 && /*data[0]==0xFF && data[1]==0xD8 && data[2]==0xFF*/ data[6]=='J' && data[7]=='F' && data[8]=='I' && data[9]=='F'; @@ -921,6 +871,7 @@ Covers::Covers() { maxPerLoopIteration=Settings::self()->maxCoverUpdatePerIteration(); maxFindPerLoopIteration=Settings::self()->maxCoverFindPerIteration(); + cache.setMaxCost(Settings::self()->coverCacheSize()*1024*1024); } void Covers::readConfig() @@ -948,6 +899,52 @@ void Covers::stop() #endif } +QPixmap * Covers::getScaledCover(const QString &artist, const QString &album, int size) +{ + if (size<4) { + return 0; + } +// DBUG_CLASS("Covers") << artist << album << size; + QString key=cacheKey(artist, album, size); + QPixmap *pix(cache.object(key)); + if (!pix && cacheScaledCovers) { + QString fileName=getScaledCoverName(artist, album, size, false); + if (!fileName.isEmpty() && QFile::exists(fileName)) { + QImage img(fileName); + if (!img.isNull() && (img.width()==size || img.height()==size)) { + DBUG_CLASS("Covers") << artist << album << size << "scaled cover found" << fileName; + pix=new QPixmap(QPixmap::fromImage(img)); + cache.insert(key, pix, pix->width()*pix->height()*(pix->depth()/8)); + } + } + + if (!pix) { + // Create a dummy pixmap so that we dont keep on stating files that do not exist! + pix=new QPixmap(1, 1); + cache.insert(key, pix, 4); + } + cacheSizes.insert(size); + } + return pix && pix->width()>1 ? pix : 0; +} + +QPixmap * Covers::saveScaledCover(const QImage &img, const QString &artist, const QString &album, int size) +{ + if (size<4) { + return 0; + } + + if (cacheScaledCovers) { + QString fileName=getScaledCoverName(artist, album, size, true); + bool status=img.save(fileName); + DBUG_CLASS("Covers") << artist << album << size << fileName << status; + } + QPixmap *pix=new QPixmap(QPixmap::fromImage(img)); + cache.insert(cacheKey(artist, album, size), pix, pix->width()*pix->height()*(pix->depth()/8)); + cacheSizes.insert(size); + return pix; +} + QPixmap * Covers::get(const Song &song, int size) { if (song.isUnknown()) { diff --git a/gui/covers.h b/gui/covers.h index 100a28e7d..ad174716a 100644 --- a/gui/covers.h +++ b/gui/covers.h @@ -31,6 +31,7 @@ #include #include #include +#include #include "song.h" #include "config.h" @@ -171,8 +172,6 @@ public: static QString albumFileName(const Song &song); static QString artistFileName(const Song &song); static QString fixArtist(const QString &artist); - static QPixmap * getScaledCover(const QString &artist, const QString &album, int size); - static QPixmap *saveScaledCover(const QImage &img, const QString &artist, const QString &album, int size); static bool isJpg(const QByteArray &data); static bool isPng(const QByteArray &data); static const char * imageFormat(const QByteArray &data); @@ -181,6 +180,8 @@ public: void readConfig(); void stop(); + QPixmap * getScaledCover(const QString &artist, const QString &album, int size); + QPixmap * saveScaledCover(const QImage &img, const QString &artist, const QString &album, int size); // Get cover image of specified size. If this is not found 0 will be returned, and the cover // will be downloaded. QPixmap * get(const Song &song, int size); @@ -227,6 +228,8 @@ private: int retrieved; QSet currentImageRequests; QList queue; + QSet cacheSizes; + QCache cache; QMap filenames; CoverDownloader *downloader; CoverLocator *locator; diff --git a/gui/settings.cpp b/gui/settings.cpp index 9e5a76b13..db85e3243 100644 --- a/gui/settings.cpp +++ b/gui/settings.cpp @@ -890,6 +890,12 @@ int Settings::maxCoverUpdatePerIteration() return RESTRICT(v, 1, 20); } +int Settings::coverCacheSize() +{ + int v=GET_INT("coverCacheSize", 4); + return RESTRICT(v, 1, 512); +} + QStringList Settings::cueFileCodecs() { return GET_STRINGLIST("cueFileCodecs", QStringList()); diff --git a/gui/settings.h b/gui/settings.h index ba50fc691..f171c9b71 100644 --- a/gui/settings.h +++ b/gui/settings.h @@ -210,6 +210,7 @@ public: bool podcastAutoDownload(); int maxCoverFindPerIteration(); int maxCoverUpdatePerIteration(); + int coverCacheSize(); QStringList cueFileCodecs(); bool networkAccessEnabled(); int volumeStep(); diff --git a/models/albumsmodel.cpp b/models/albumsmodel.cpp index e9835daf1..6d898cac0 100644 --- a/models/albumsmodel.cpp +++ b/models/albumsmodel.cpp @@ -598,7 +598,7 @@ void AlbumsModel::AlbumItem::updateStats() QPixmap * AlbumsModel::AlbumItem::cover() { if (Song::SingleTracks!=type && songs.count()) { - QPixmap *pix=Covers::getScaledCover(artist, album, iconSize()); + QPixmap *pix=Covers::self()->getScaledCover(artist, album, iconSize()); if (pix) { return pix; } @@ -635,7 +635,7 @@ QPixmap * AlbumsModel::AlbumItem::setCover(const QImage &img) coverRequested=false; if (Song::SingleTracks!=type && songs.count() && !img.isNull()) { int size=iconSize(); - return Covers::saveScaledCover(img.scaled(QSize(size, size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), artist, album, size); + return Covers::self()->saveScaledCover(img.scaled(QSize(size, size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation), artist, album, size); } return 0; } diff --git a/models/musiclibraryitemalbum.cpp b/models/musiclibraryitemalbum.cpp index 6f70e0bf0..9bf8c2b78 100644 --- a/models/musiclibraryitemalbum.cpp +++ b/models/musiclibraryitemalbum.cpp @@ -169,7 +169,7 @@ QPixmap * MusicLibraryItemAlbum::setCoverImage(const QImage &img) const int size=iconSize(largeImages()); QImage scaled=img.scaled(QSize(size, size), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); m_coverRequested=false; - return Covers::saveScaledCover(scaled, parentItem()->data(), data(), size); + return Covers::self()->saveScaledCover(scaled, parentItem()->data(), data(), size); } QString MusicLibraryItemAlbum::displayData(bool full) const @@ -190,7 +190,7 @@ const QPixmap & MusicLibraryItemAlbum::cover() const { int iSize=iconSize(largeImages()); if (Song::SingleTracks!=m_type && parentItem() && iSize && childCount()) { - QPixmap *pix=Covers::getScaledCover(parentItem()->data(), data(), iSize); + QPixmap *pix=Covers::self()->getScaledCover(parentItem()->data(), data(), iSize); if (pix) { return *pix; } diff --git a/models/musiclibraryitemartist.cpp b/models/musiclibraryitemartist.cpp index 61258ee37..69967d0d7 100644 --- a/models/musiclibraryitemartist.cpp +++ b/models/musiclibraryitemartist.cpp @@ -91,7 +91,7 @@ bool MusicLibraryItemArtist::setCover(const QImage &img, bool update) const scaled=scaled.copy((scaled.width()-size)/2, 0, size, size); } m_coverRequested=false; - Covers::saveScaledCover(scaled, data(), QString(), size); + Covers::self()->saveScaledCover(scaled, data(), QString(), size); return true; } @@ -116,7 +116,7 @@ const QPixmap & MusicLibraryItemArtist::cover() const return *theVariousArtistsIcon; } - QPixmap *pix=Covers::getScaledCover(data(), QString(), iSize); + QPixmap *pix=Covers::self()->getScaledCover(data(), QString(), iSize); if (pix) { return *pix; } @@ -160,8 +160,7 @@ const QPixmap & MusicLibraryItemArtist::cover() const if (!img.img.isNull()) { setCover(img.img); - m_coverRequested=false; - pix=Covers::getScaledCover(data(), QString(), iSize); + pix=Covers::self()->getScaledCover(data(), QString(), iSize); if (pix) { return *pix; } @@ -292,3 +291,5 @@ bool MusicLibraryItemArtist::largeImages() const return m_parentItem && Type_Root==m_parentItem->itemType() && static_cast(m_parentItem)->useLargeImages(); } +Images(); +}