File indexing completed on 2024-05-19 04:49:30
0001 /**************************************************************************************** 0002 * Copyright (c) 2009 Bart Cerneels <bart.cerneels@kde.org> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #include "core/podcasts/PodcastImageFetcher.h" 0018 0019 #include "core/support/Debug.h" 0020 0021 #include <QCryptographicHash> 0022 #include <QNetworkConfigurationManager> 0023 0024 #include <KIO/Job> 0025 0026 PodcastImageFetcher::PodcastImageFetcher() 0027 { 0028 } 0029 0030 void 0031 PodcastImageFetcher::addChannel( Podcasts::PodcastChannelPtr channel ) 0032 { 0033 DEBUG_BLOCK 0034 if( channel->imageUrl().isEmpty() ) 0035 { 0036 debug() << channel->title() << " does not have an imageUrl"; 0037 return; 0038 } 0039 0040 if( hasCachedImage( channel ) ) 0041 { 0042 debug() << "using cached image for " << channel->title(); 0043 QString imagePath = cachedImagePath( channel ).toLocalFile(); 0044 QImage image( imagePath ); 0045 if( image.isNull() ) 0046 error() << "could not load pixmap from " << imagePath; 0047 else 0048 channel->setImage( image ); 0049 return; 0050 } 0051 0052 if( m_channels.contains( channel ) ) 0053 { 0054 debug() << "Channel already queued:" << channel->title(); 0055 return; 0056 } 0057 0058 if( m_jobChannelMap.values().contains( channel ) ) 0059 { 0060 debug() << "Copy job already running for channel:" << channel->title(); 0061 return; 0062 } 0063 0064 debug() << "Adding " << channel->title() << " to fetch queue"; 0065 m_channels.append( channel ); 0066 } 0067 0068 void 0069 PodcastImageFetcher::addEpisode( const Podcasts::PodcastEpisodePtr &episode ) 0070 { 0071 Q_UNUSED( episode ); 0072 } 0073 0074 QUrl 0075 PodcastImageFetcher::cachedImagePath( const Podcasts::PodcastChannelPtr &channel ) 0076 { 0077 return cachedImagePath( channel.data() ); 0078 } 0079 0080 QUrl 0081 PodcastImageFetcher::cachedImagePath( Podcasts::PodcastChannel *channel ) 0082 { 0083 QUrl imagePath = channel->saveLocation(); 0084 if( imagePath.isEmpty() || !imagePath.isLocalFile() ) 0085 imagePath = QUrl::fromLocalFile( Amarok::saveLocation( QStringLiteral("podcasts") ) ); 0086 QCryptographicHash md5( QCryptographicHash::Md5 ); 0087 md5.addData( channel->url().url().toLocal8Bit() ); 0088 QString extension = Amarok::extension( channel->imageUrl().fileName() ); 0089 imagePath = imagePath.adjusted( QUrl::StripTrailingSlash ); 0090 imagePath.setPath( imagePath.path() + QLatin1Char('/') + ( md5.result().toHex() + QLatin1Char('.') + extension ) ); 0091 return imagePath; 0092 } 0093 0094 bool 0095 PodcastImageFetcher::hasCachedImage( const Podcasts::PodcastChannelPtr &channel ) 0096 { 0097 DEBUG_BLOCK 0098 return QFile( PodcastImageFetcher::cachedImagePath( 0099 Podcasts::PodcastChannelPtr::dynamicCast( channel ) ).toLocalFile() ).exists(); 0100 } 0101 0102 void 0103 PodcastImageFetcher::run() 0104 { 0105 if( m_channels.isEmpty() && m_episodes.isEmpty() 0106 && m_jobChannelMap.isEmpty() && m_jobEpisodeMap.isEmpty() ) 0107 { 0108 //nothing to do 0109 Q_EMIT( done( this ) ); 0110 return; 0111 } 0112 0113 QNetworkConfigurationManager mgr; 0114 if( !mgr.isOnline() ) 0115 { 0116 debug() << "QNetworkConfigurationManager reports we are not online, canceling podcast image download"; 0117 Q_EMIT( done( this ) ); 0118 //TODO: schedule another run after Solid reports we are online again 0119 return; 0120 } 0121 0122 foreach( Podcasts::PodcastChannelPtr channel, m_channels ) 0123 { 0124 QUrl channelImageUrl = channel->imageUrl(); 0125 // KIO::file_copy in KF5 needs scheme 0126 if (channelImageUrl.isRelative() && channelImageUrl.host().isEmpty()) { 0127 channelImageUrl.setScheme("file"); 0128 } 0129 0130 QUrl cachedPath = cachedImagePath( channel ); 0131 KIO::mkdir( cachedPath.adjusted(QUrl::RemoveFilename|QUrl::StripTrailingSlash) ); 0132 KIO::FileCopyJob *job = KIO::file_copy(channelImageUrl, cachedPath, 0133 -1, KIO::HideProgressInfo | KIO::Overwrite ); 0134 //remove channel from the todo list 0135 m_channels.removeAll( channel ); 0136 m_jobChannelMap.insert( job, channel ); 0137 connect( job, &KIO::FileCopyJob::finished, this, &PodcastImageFetcher::slotDownloadFinished ); 0138 } 0139 0140 //TODO: episodes 0141 } 0142 0143 void 0144 PodcastImageFetcher::slotDownloadFinished( KJob *job ) 0145 { 0146 DEBUG_BLOCK 0147 0148 //QMap::take() also removes the entry from the map. 0149 Podcasts::PodcastChannelPtr channel = m_jobChannelMap.take( job ); 0150 if( channel.isNull() ) 0151 { 0152 error() << "got null PodcastChannelPtr " << __FILE__ << ":" << __LINE__; 0153 return; 0154 } 0155 0156 if( job->error() ) 0157 { 0158 error() << "downloading podcast image " << job->errorString(); 0159 } 0160 else 0161 { 0162 QString imagePath = cachedImagePath( channel ).toLocalFile(); 0163 QImage image( imagePath ); 0164 if( image.isNull() ) 0165 error() << "could not load pixmap from " << imagePath; 0166 else 0167 channel->setImage( image ); 0168 } 0169 0170 //call run again to start the next batch of transfers. 0171 run(); 0172 }