File indexing completed on 2025-03-09 04:24:06
0001 /**************************************************************************************** 0002 * Copyright (c) 2009 Simon Esneault <simon.esneault@gmail.com> * 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 #define DEBUG_PREFIX "Photos" 0018 0019 #include "PhotosEngine.h" 0020 0021 #include "EngineController.h" 0022 #include "core/support/Amarok.h" 0023 #include "core/support/Debug.h" 0024 0025 #include <QXmlStreamReader> 0026 #include <QUrlQuery> 0027 0028 0029 PhotosEngine::PhotosEngine( QObject* parent ) 0030 : QObject( parent ) 0031 , m_nbPhotos( 10 ) 0032 , m_status( Stopped ) 0033 { 0034 DEBUG_BLOCK 0035 0036 EngineController *controller = The::engineController(); 0037 connect( controller, &EngineController::trackMetadataChanged, this, &PhotosEngine::trackChanged ); 0038 connect( controller, &EngineController::trackChanged, this, &PhotosEngine::trackChanged ); 0039 connect( controller, &EngineController::stopped, this, &PhotosEngine::stopped ); 0040 } 0041 0042 PhotosEngine::~PhotosEngine() 0043 { 0044 } 0045 0046 void 0047 PhotosEngine::stopped() 0048 { 0049 DEBUG_BLOCK 0050 0051 setPhotos( QList<PhotoInfo>() ); 0052 setStatus( Stopped ); 0053 setArtist( QString() ); 0054 m_currentTrack.clear(); 0055 } 0056 0057 void 0058 PhotosEngine::trackChanged( const Meta::TrackPtr &track ) 0059 { 0060 if( !track ) 0061 return; 0062 0063 update(); 0064 } 0065 0066 int 0067 PhotosEngine::fetchSize() const 0068 { 0069 return m_nbPhotos; 0070 } 0071 0072 void 0073 PhotosEngine::setFetchSize( int size ) 0074 { 0075 m_nbPhotos = size; 0076 } 0077 0078 QStringList 0079 PhotosEngine::keywords() const 0080 { 0081 return m_keywords; 0082 } 0083 0084 void 0085 PhotosEngine::setKeywords( const QStringList &keywords ) 0086 { 0087 if( m_keywords == keywords ) 0088 return; 0089 0090 m_keywords = keywords; 0091 Q_EMIT keywordsChanged(); 0092 } 0093 0094 void 0095 PhotosEngine::metadataChanged(const Meta::TrackPtr &track ) 0096 { 0097 const bool hasChanged = !track->artist() || track->artist()->name() != m_artist; 0098 if ( hasChanged ) 0099 update(); 0100 } 0101 0102 void 0103 PhotosEngine::update( bool force ) 0104 { 0105 // prevent 0106 Meta::TrackPtr currentTrack = The::engineController()->currentTrack(); 0107 if( !currentTrack || !currentTrack->artist() ) 0108 { 0109 debug() << "invalid current track"; 0110 setPhotos( QList<PhotoInfo>() ); 0111 return; 0112 } 0113 else if( !force && currentTrack->artist()->name() == m_artist ) 0114 { 0115 debug() << "artist name unchanged"; 0116 return; 0117 } 0118 else 0119 { 0120 unsubscribeFrom( m_currentTrack ); 0121 m_currentTrack = currentTrack; 0122 subscribeTo( currentTrack ); 0123 0124 if ( !currentTrack ) 0125 return; 0126 0127 // Save artist 0128 setArtist( currentTrack->artist()->name() ); 0129 setPhotos( QList<PhotoInfo>() ); 0130 0131 // Show the information 0132 if( !m_artist.isEmpty() ) 0133 { 0134 setStatus( Fetching ); 0135 } 0136 else 0137 { 0138 setPhotos( QList<PhotoInfo>() ); 0139 return; 0140 } 0141 0142 QStringList tags = m_keywords; 0143 tags << m_artist; 0144 tags.removeDuplicates(); 0145 0146 // Query flickr, order by relevance, 10 max 0147 // Flickr :http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=9c5a288116c34c17ecee37877397fe31&text=ARTIST&per_page=20 0148 QUrl flickrUrl; 0149 QUrlQuery query; 0150 flickrUrl.setScheme( "https" ); 0151 flickrUrl.setHost( "api.flickr.com" ); 0152 flickrUrl.setPath( "/services/rest/" ); 0153 query.addQueryItem( "method", "flickr.photos.search" ); 0154 query.addQueryItem( "api_key", Amarok::flickrApiKey() ); 0155 query.addQueryItem( "per_page", QString::number( m_nbPhotos ) ); 0156 query.addQueryItem( "sort", "date-posted-desc" ); 0157 query.addQueryItem( "media", "photos" ); 0158 query.addQueryItem( "content_type", QString::number(1) ); 0159 query.addQueryItem( "text", tags.join(" ") ); 0160 flickrUrl.setQuery( query ); 0161 debug() << "Flickr url:" << flickrUrl; 0162 0163 m_flickrUrls << flickrUrl; 0164 The::networkAccessManager()->getData( flickrUrl, this, &PhotosEngine::resultFlickr ); 0165 0166 } 0167 } 0168 0169 void 0170 PhotosEngine::resultFlickr(const QUrl &url, const QByteArray &data, const NetworkAccessManagerProxy::Error &e ) 0171 { 0172 if( !m_flickrUrls.contains( url ) ) 0173 return; 0174 0175 DEBUG_BLOCK 0176 0177 m_flickrUrls.remove( url ); 0178 if( e.code != QNetworkReply::NoError ) 0179 { 0180 setError( e.description ); 0181 debug() << "Unable to retrieve Flickr information:" << e.description; 0182 return; 0183 } 0184 0185 if( data.isNull() ) 0186 { 0187 debug() << "Got bad xml!"; 0188 return; 0189 } 0190 0191 setPhotos( QList<PhotoInfo>() ); 0192 QXmlStreamReader xml( data ); 0193 QList<PhotoInfo> photosInfo = photosListFromXml( xml ); 0194 debug() << "got" << photosInfo.size() << "photo info"; 0195 setPhotos( photosInfo ); 0196 setStatus( Completed ); 0197 } 0198 0199 QList<PhotosEngine::PhotoInfo> 0200 PhotosEngine::photosListFromXml( QXmlStreamReader &xml ) 0201 { 0202 QList<PhotoInfo> photoList; 0203 xml.readNextStartElement(); // rsp 0204 if( xml.attributes().value(QLatin1String("stat")) != QLatin1String("ok") ) 0205 return photoList; 0206 0207 xml.readNextStartElement(); // photos 0208 while( xml.readNextStartElement() ) 0209 { 0210 if( xml.name() == QLatin1String("photo") ) 0211 { 0212 const QXmlStreamAttributes &attr = xml.attributes(); 0213 QStringRef id = attr.value( QLatin1String("id") ); 0214 QStringRef farm = attr.value( QLatin1String("farm") ); 0215 QStringRef owner = attr.value( QLatin1String("owner") ); 0216 QStringRef secret = attr.value( QLatin1String("secret") ); 0217 QStringRef server = attr.value( QLatin1String("server") ); 0218 QStringRef title = attr.value( QLatin1String("title") ); 0219 0220 QUrl photoUrl; 0221 photoUrl.setScheme( "http" ); 0222 photoUrl.setHost( QStringLiteral("farm%1.static.flickr.com").arg( farm.toString() ) ); 0223 photoUrl.setPath( QStringLiteral("/%1/%2_%3.jpg").arg( server.toString(), id.toString(), secret.toString() ) ); 0224 0225 QUrl pageUrl; 0226 pageUrl.setScheme( "http" ); 0227 pageUrl.setHost( QLatin1String("www.flickr.com") ); 0228 pageUrl.setPath( QStringLiteral("/photos/%1/%2").arg( owner.toString(), id.toString() ) ); 0229 0230 PhotoInfo info; 0231 info.title = title.toString(); 0232 info.urlpage = pageUrl; 0233 info.urlphoto = photoUrl; 0234 photoList.append( info ); 0235 } 0236 xml.skipCurrentElement(); 0237 } 0238 return photoList; 0239 } 0240 0241 void 0242 PhotosEngine::setPhotos( const QList<PhotoInfo> &photos ) 0243 { 0244 if( m_photos == photos ) 0245 return; 0246 0247 m_photos = photos; 0248 Q_EMIT photosChanged(); 0249 } 0250 0251 void 0252 PhotosEngine::setStatus( Status status ) 0253 { 0254 if( m_status == status ) 0255 return; 0256 0257 m_status = status; 0258 Q_EMIT statusChanged(); 0259 } 0260 0261 void 0262 PhotosEngine::setError( const QString &error ) 0263 { 0264 if( m_error == error ) 0265 return; 0266 0267 m_error = error; 0268 Q_EMIT errorChanged(); 0269 } 0270 0271 void 0272 PhotosEngine::setArtist( const QString &artist ) 0273 { 0274 if( m_artist == artist ) 0275 return; 0276 0277 m_artist = artist; 0278 Q_EMIT artistChanged(); 0279 } 0280 0281 QList<QUrl> 0282 PhotosEngine::photoUrls() const 0283 { 0284 QList<QUrl> list; 0285 for( const auto &photo : m_photos ) 0286 { 0287 list << photo.urlphoto; 0288 } 0289 return list; 0290 } 0291 0292 QList<QUrl> 0293 PhotosEngine::pageUrls() const 0294 { 0295 QList<QUrl> list; 0296 for( const auto &photo : m_photos ) 0297 { 0298 list << photo.urlpage; 0299 } 0300 return list; 0301 } 0302 0303 QList<QString> 0304 PhotosEngine::photoTitles() const 0305 { 0306 QList<QString> list; 0307 for( const auto &photo : m_photos ) 0308 { 0309 list << photo.title; 0310 } 0311 return list; 0312 }