File indexing completed on 2024-05-05 04:49:15
0001 /**************************************************************************************** 0002 * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@kde.org> * 0003 * Copyright (c) 2007 Casey Link <unnamedrambler@gmail.com> * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify it under * 0006 * the terms of the GNU General Public License as published by the Free Software * 0007 * Foundation; either version 2 of the License, or (at your option) any later * 0008 * version. * 0009 * * 0010 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0011 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0012 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0013 * * 0014 * You should have received a copy of the GNU General Public License along with * 0015 * this program. If not, see <http://www.gnu.org/licenses/>. * 0016 ****************************************************************************************/ 0017 0018 #define DEBUG_PREFIX "ServiceAlbumCoverDownloader" 0019 0020 #include "ServiceAlbumCoverDownloader.h" 0021 0022 #include "core/support/Amarok.h" 0023 #include "amarokconfig.h" 0024 #include "core/support/Debug.h" 0025 #include "covermanager/CoverCache.h" 0026 0027 #include <thread> 0028 0029 #include <QDir> 0030 #include <QImage> 0031 0032 using namespace Meta; 0033 0034 0035 Meta::ServiceAlbumWithCover::ServiceAlbumWithCover( const QString &name ) 0036 : ServiceAlbum( name ) 0037 , m_hasFetchedCover( false ) 0038 , m_isFetchingCover ( false ) 0039 {} 0040 0041 Meta::ServiceAlbumWithCover::ServiceAlbumWithCover( const QStringList &resultRow ) 0042 : ServiceAlbum( resultRow ) 0043 , m_hasFetchedCover( false ) 0044 , m_isFetchingCover ( false ) 0045 {} 0046 0047 Meta::ServiceAlbumWithCover::~ServiceAlbumWithCover() 0048 { 0049 CoverCache::invalidateAlbum( this ); 0050 } 0051 0052 QImage 0053 ServiceAlbumWithCover::image( int size ) const 0054 { 0055 if( size > 1000 ) 0056 { 0057 debug() << "Giant image detected, are you sure you want this?"; 0058 return Meta::Album::image( size ); 0059 } 0060 0061 const QString artist = hasAlbumArtist() ? 0062 albumArtist()->name() : 0063 QStringLiteral("NULL"); //no need to translate, only used as a caching key/temp filename 0064 0065 const QString coverName = QStringLiteral( "%1_%2_%3_cover.png" ).arg( downloadPrefix(), artist, name() ); 0066 const QString saveLocation = Amarok::saveLocation( QStringLiteral("albumcovers/cache/") ); 0067 const QDir cacheCoverDir = QDir( saveLocation ); 0068 0069 //make sure that this dir exists 0070 if( !cacheCoverDir.exists() ) 0071 cacheCoverDir.mkpath( saveLocation ); 0072 0073 if( size <= 1 ) 0074 size = 100; 0075 0076 const QString sizeKey = QString::number( size ) + QLatin1Char('@'); 0077 const QString cacheCoverPath = cacheCoverDir.filePath( sizeKey + coverName ); 0078 0079 if( QFile::exists( cacheCoverPath ) ) 0080 { 0081 return QImage( cacheCoverPath ); 0082 } 0083 else if( m_hasFetchedCover && !m_cover.isNull() ) 0084 { 0085 QImage image( m_cover.scaled( size, size, Qt::KeepAspectRatio, Qt::SmoothTransformation ) ); 0086 std::thread thread( QOverload<const QString&, const char*, int>::of( &QImage::save ), image, cacheCoverPath, "PNG", -1 ); 0087 thread.detach(); 0088 return image; 0089 } 0090 else if( !m_isFetchingCover && !coverUrl().isEmpty() ) 0091 { 0092 m_isFetchingCover = true; 0093 0094 ( new ServiceAlbumCoverDownloader )->downloadCover( 0095 ServiceAlbumWithCoverPtr(const_cast<ServiceAlbumWithCover*>(this)) ); 0096 } 0097 0098 return Meta::Album::image( size ); 0099 } 0100 0101 void 0102 ServiceAlbumWithCover::setImage( const QImage& image ) 0103 { 0104 m_cover = image; 0105 m_hasFetchedCover = true; 0106 m_isFetchingCover = false; 0107 CoverCache::invalidateAlbum( this ); 0108 0109 notifyObservers(); 0110 } 0111 0112 void 0113 ServiceAlbumWithCover::imageDownloadCanceled() const 0114 { 0115 m_hasFetchedCover = true; 0116 m_isFetchingCover = false; 0117 } 0118 0119 0120 /////////////////////////////////////////////////////////////////////////////// 0121 // Class ServiceAlbumCoverDownloader 0122 /////////////////////////////////////////////////////////////////////////////// 0123 0124 ServiceAlbumCoverDownloader::ServiceAlbumCoverDownloader() 0125 : m_albumDownloadJob( ) 0126 { 0127 m_tempDir = new QTemporaryDir(); 0128 m_tempDir->setAutoRemove( true ); 0129 } 0130 0131 ServiceAlbumCoverDownloader::~ServiceAlbumCoverDownloader() 0132 { 0133 delete m_tempDir; 0134 } 0135 0136 void 0137 ServiceAlbumCoverDownloader::downloadCover( ServiceAlbumWithCoverPtr album ) 0138 { 0139 m_album = album; 0140 0141 QUrl downloadUrl( album->coverUrl() ); 0142 // KIO::file_copy in KF5 needs scheme 0143 if (downloadUrl.isRelative() && downloadUrl.host().isEmpty()) 0144 downloadUrl.setScheme("file"); 0145 0146 m_coverDownloadPath = m_tempDir->path() + QLatin1Char('/') + downloadUrl.fileName(); 0147 0148 debug() << "Download Cover: " << downloadUrl.url() << " to: " << m_coverDownloadPath; 0149 0150 m_albumDownloadJob = KIO::file_copy( downloadUrl, QUrl::fromLocalFile( m_coverDownloadPath ), -1, KIO::Overwrite | KIO::HideProgressInfo ); 0151 0152 connect( m_albumDownloadJob, &KJob::result, this, &ServiceAlbumCoverDownloader::coverDownloadComplete ); 0153 } 0154 0155 void 0156 ServiceAlbumCoverDownloader::coverDownloadComplete( KJob * downloadJob ) 0157 { 0158 if( !m_album ) // album was removed in between 0159 { 0160 debug() << "Bad album pointer"; 0161 return; 0162 } 0163 0164 if ( downloadJob != m_albumDownloadJob ) 0165 return; //not the right job, so let's ignore it 0166 0167 if( !downloadJob || downloadJob->error() ) 0168 { 0169 debug() << "Download Job failed!"; 0170 0171 //we could not download, so inform album 0172 coverDownloadCanceled( downloadJob ); 0173 return; 0174 } 0175 0176 const QImage cover = QImage( m_coverDownloadPath ); 0177 if ( cover.isNull() ) 0178 { 0179 debug() << "file not a valid image"; 0180 //the file wasn't an image, so inform album 0181 m_album->imageDownloadCanceled(); 0182 return; 0183 } 0184 0185 m_album->setImage( cover ); 0186 0187 downloadJob->deleteLater(); 0188 0189 deleteLater(); 0190 } 0191 0192 void 0193 ServiceAlbumCoverDownloader::coverDownloadCanceled( KJob *downloadJob ) 0194 { 0195 Q_UNUSED( downloadJob ); 0196 DEBUG_BLOCK 0197 0198 if( !m_album ) // album was removed in between 0199 return; 0200 0201 debug() << "Cover download cancelled"; 0202 m_album->imageDownloadCanceled(); 0203 deleteLater(); 0204 } 0205 0206