Commit 161130b10e910424c0e2a8d3cffdc413d0949b51
- Diff rendering mode:
- inline
- side by side
src/covermanager/CoverFetcher.cpp
(41 / 385)
|   | |||
| 3 | 3 | * Copyright (c) 2004 Stefan Bogner <bochi@online.ms> * | |
| 4 | 4 | * Copyright (c) 2004 Max Howell <max.howell@methylblue.com> * | |
| 5 | 5 | * Copyright (c) 2007 Dan Meltzer <parallelgrapefruit@gmail.com> * | |
| 6 | * Copyright (c) 2009 Martin Sandsmark <sandsmark@samfundet.no> * | ||
| 6 | 7 | * * | |
| 7 | 8 | * This program is free software; you can redistribute it and/or modify it under * | |
| 8 | 9 | * the terms of the GNU General Public License as published by the Free Software * | |
| … | … | ||
| 90 | 90 | { | |
| 91 | 91 | m_userCanEditQuery = true; | |
| 92 | 92 | m_albums << album; | |
| 93 | buildQueries( album ); | ||
| 93 | startFetch( album ); | ||
| 94 | 94 | } | |
| 95 | 95 | ||
| 96 | 96 | void | |
| … | … | ||
| 113 | 113 | m_isFetching = true; | |
| 114 | 114 | Meta::AlbumPtr firstAlbum = m_albums.takeFirst(); | |
| 115 | 115 | m_albumsMutex.unlock(); | |
| 116 | buildQueries( firstAlbum ); | ||
| 116 | startFetch( album ); | ||
| 117 | 117 | } | |
| 118 | 118 | else | |
| 119 | 119 | { | |
| … | … | ||
| 147 | 147 | { | |
| 148 | 148 | Meta::AlbumPtr album = m_albums.takeFirst(); | |
| 149 | 149 | m_albumsMutex.unlock(); | |
| 150 | buildQueries( album ); | ||
| 150 | startFetch( album ); | ||
| 151 | 151 | } | |
| 152 | 152 | else | |
| 153 | 153 | { | |
| … | … | ||
| 165 | 165 | // PRIVATE SLOTS | |
| 166 | 166 | ////////////////////////////////////////////////////////////////////////////////////////// | |
| 167 | 167 | ||
| 168 | |||
| 169 | void CoverFetcher::buildQueries( Meta::AlbumPtr album ) | ||
| 170 | { | ||
| 171 | m_fetchMutex.lock(); | ||
| 172 | m_isFetching = true; | ||
| 173 | m_fetchMutex.unlock(); | ||
| 174 | m_albumPtr = album; | ||
| 175 | |||
| 176 | // Amazon doesn't like accents, so we use cleanPath() to remove them | ||
| 177 | QString albumName = Amarok::cleanPath( album->name() ); | ||
| 178 | QString artistName = Amarok::cleanPath( album->hasAlbumArtist() ? album->albumArtist()->name() : QString() ); | ||
| 179 | |||
| 180 | QStringList extensions; | ||
| 181 | extensions << i18n("disc") << i18n("disk") << i18n("remaster") << i18n("cd") << i18n("single") << i18n("soundtrack") << i18n("part") | ||
| 182 | << "disc" << "disk" << "remaster" << "cd" << "single" << "soundtrack" << "part" << "cds" /*cd single*/; | ||
| 183 | |||
| 184 | m_queries.clear(); | ||
| 185 | m_userQuery.clear(); | ||
| 186 | |||
| 187 | //we do several queries, one raw ie, without the following modifications | ||
| 188 | //the others have the above strings removed with the following regex, as this can increase hit-rate | ||
| 189 | const QString template1 = " ?-? ?[(^{]* ?%1 ?\\d*[)^}\\]]* *$"; //eg album - [disk 1] -> album | ||
| 190 | foreach( const QString &extension, extensions ) { | ||
| 191 | QRegExp regexp( template1.arg( extension ) ); | ||
| 192 | regexp.setCaseSensitivity( Qt::CaseInsensitive ); | ||
| 193 | albumName.remove( regexp ); | ||
| 194 | } | ||
| 195 | |||
| 196 | //TODO try queries that remove anything in album after a " - " eg Les Mis. - Excerpts | ||
| 197 | |||
| 198 | /** | ||
| 199 | * We search for artist - album, and just album, using the exact album text and the | ||
| 200 | * manipulated album text. | ||
| 201 | */ | ||
| 202 | |||
| 203 | //search on our modified term, then the original | ||
| 204 | if ( !artistName.isEmpty() ) | ||
| 205 | m_userQuery = artistName + " - "; | ||
| 206 | m_userQuery += albumName; | ||
| 207 | |||
| 208 | m_queries += m_userQuery; | ||
| 209 | m_queries += artistName + " - " + albumName; | ||
| 210 | m_queries += albumName; | ||
| 211 | |||
| 212 | //don't do the same searches twice in a row | ||
| 213 | m_queries.pop_front(); | ||
| 214 | m_queries.pop_back(); | ||
| 215 | |||
| 216 | /** | ||
| 217 | * Finally we do a search for just the artist, just in case as this often | ||
| 218 | * turns up a cover, and it might just be the right one! Also it would be | ||
| 219 | * the only valid search if m_album.isEmpty() | ||
| 220 | */ | ||
| 221 | m_queries += artistName; | ||
| 222 | debug() << m_queries; | ||
| 223 | startFetch( album ); | ||
| 224 | } | ||
| 225 | 168 | void | |
| 226 | 169 | CoverFetcher::startFetch( Meta::AlbumPtr album ) | |
| 227 | 170 | { | |
| … | … | ||
| 173 | 173 | m_fetchMutex.unlock(); | |
| 174 | 174 | m_albumPtr = album; | |
| 175 | 175 | ||
| 176 | // Amarok's Amazon license Key. | ||
| 177 | const QString LICENSE( "0N04TFAWZR6YVWWS3CG2" ); | ||
| 178 | |||
| 179 | 176 | // reset all values | |
| 180 | m_coverAmazonUrls.clear(); | ||
| 181 | m_coverAsins.clear(); | ||
| 182 | m_coverUrls.clear(); | ||
| 183 | m_coverNames.clear(); | ||
| 184 | 177 | m_xml.clear(); | |
| 185 | 178 | m_size = 2; | |
| 186 | 179 | ||
| 187 | if( m_queries.isEmpty() ) | ||
| 188 | { | ||
| 189 | debug() << "m_queries is empty"; | ||
| 190 | finishWithError( i18n("No cover found") ); | ||
| 191 | return; | ||
| 192 | } | ||
| 193 | QString query = m_queries.front(); | ||
| 194 | m_queries.pop_front(); | ||
| 180 | QUrl url; | ||
| 181 | url.setScheme( "http" ); | ||
| 182 | url.setHost( "ws.audioscrobbler.com" ); | ||
| 183 | url.setPath( "/2.0/" ); | ||
| 184 | url.addQueryItem( "method", "album.getinfo" ); | ||
| 185 | url.addQueryItem( "api_key", "402d3ca8e9bc9d3cf9b85e1202944ca5" ); | ||
| 186 | url.addQueryItem( "album", album->name().toLocal8Bit() ); | ||
| 195 | 187 | ||
| 196 | // '&' breaks searching | ||
| 197 | query.remove('&'); | ||
| 188 | if ( album->hasAlbumArtist() ) | ||
| 189 | url.addQueryItem( "artist", album->albumArtist()->name().toLocal8Bit() ); | ||
| 198 | 190 | ||
| 199 | // Bug 97901: Import cover from amazon france doesn't work properly | ||
| 200 | // (we have to set "mode=music-fr" instead of "mode=music") | ||
| 201 | QString locale = AmarokConfig::amazonLocale(); | ||
| 202 | //Amazon Japan isn't on xml.amazon.com | ||
| 203 | QString tld = "com"; | ||
| 204 | |||
| 205 | if( locale == "us" ) | ||
| 206 | tld = "com"; | ||
| 207 | else if( locale =="uk" ) | ||
| 208 | tld = "co.uk"; | ||
| 209 | else | ||
| 210 | tld = locale; | ||
| 211 | |||
| 212 | QString url; | ||
| 213 | url = "http://ecs.amazonaws." + tld | ||
| 214 | + "/onca/xml?Service=AWSECommerceService&Version=2007-10-29&Operation=ItemSearch&AssociateTag=amarok-20&AWSAccessKeyId=" + LICENSE | ||
| 215 | + "&Keywords=" + QUrl::toPercentEncoding( query, "/" ) | ||
| 216 | + "&SearchIndex=Music&ResponseGroup=Small,Images"; | ||
| 217 | 191 | debug() << url; | |
| 218 | 192 | ||
| 219 | 193 | KJob* job = KIO::storedGet( url, KIO::NoReload, KIO::HideProgressInfo ); | |
| … | … | ||
| 195 | 195 | ||
| 196 | 196 | if( m_userCanEditQuery ) | |
| 197 | 197 | The::statusBar()->newProgressOperation( job, i18n( "Fetching Cover" ) ); | |
| 198 | |||
| 199 | 198 | } | |
| 200 | 199 | ||
| 201 | 200 | void | |
| … | … | ||
| 203 | 203 | // NOTE: job can become 0 when this method is called from attemptAnotherFetch() | |
| 204 | 204 | if( job && job->error() ) | |
| 205 | 205 | { | |
| 206 | finishWithError( i18n("There was an error communicating with Amazon."), job ); | ||
| 206 | finishWithError( i18n( "There was an error communicating with last.fm." ), job ); | ||
| 207 | 207 | return; | |
| 208 | 208 | } | |
| 209 | 209 | ||
| 210 | //FIXME: Do we still need this? Check after 2.0 final... why is it commented out. | ||
| 211 | /* | ||
| 212 | if( m_albums.isEmpty() ) | ||
| 213 | { | ||
| 214 | finishWithError( i18n("Internal error, no albums in queue"), job ); | ||
| 215 | return; | ||
| 216 | } | ||
| 217 | */ | ||
| 218 | |||
| 219 | 210 | if( job ) | |
| 220 | 211 | { | |
| 221 | 212 | KIO::StoredTransferJob* const storedJob = static_cast<KIO::StoredTransferJob*>( job ); | |
| … | … | ||
| 216 | 216 | QDomDocument doc; | |
| 217 | 217 | if( !doc.setContent( m_xml ) ) | |
| 218 | 218 | { | |
| 219 | m_errors += i18n("The XML obtained from Amazon is invalid."); | ||
| 219 | m_errors += i18n( "The XML obtained from Last.fm is invalid." ); | ||
| 220 | 220 | if( m_albums.size() > 0 ) | |
| 221 | buildQueries( m_albums.takeFirst() ); | ||
| 221 | startFetch( m_albums.takeFirst() ); | ||
| 222 | |||
| 222 | 223 | return; | |
| 223 | 224 | } | |
| 224 | 225 | ||
| 225 | const QDomNode details = doc.documentElement().namedItem( "Details" ); | ||
| 226 | const QDomNodeList list = doc.documentElement().namedItem( "album" ).childNodes(); | ||
| 226 | 227 | ||
| 227 | // the url for the Amazon product info page | ||
| 228 | const QDomNodeList list = doc.documentElement().namedItem( "Items" ).childNodes(); | ||
| 229 | |||
| 230 | for(int i = 0; i < list.count(); i++ ) | ||
| 231 | { | ||
| 232 | QDomNode n = list.item( i ); | ||
| 233 | if( n.isElement() && n.nodeName() == "IsValid" ) | ||
| 234 | { | ||
| 235 | if( n.toElement().text() == "False" ) | ||
| 236 | { | ||
| 237 | warning() << "The XML Is Invalid!"; | ||
| 238 | return; | ||
| 239 | } | ||
| 240 | } | ||
| 241 | else if( list.item( i ).nodeName() == "Item" ) | ||
| 242 | { | ||
| 243 | const QDomNode node = list.item( i ); | ||
| 244 | parseItemNode( node ); | ||
| 245 | } | ||
| 246 | } | ||
| 247 | attemptAnotherFetch(); | ||
| 248 | } | ||
| 249 | |||
| 250 | |||
| 251 | void CoverFetcher::parseItemNode( const QDomNode &node ) | ||
| 252 | { | ||
| 253 | QDomNode it = node.firstChild(); | ||
| 254 | |||
| 255 | 228 | QString size; | |
| 256 | 229 | switch( m_size ) | |
| 257 | 230 | { | |
| 258 | case 0: size = "Small"; break; | ||
| 259 | case 1: size = "Medium"; break; | ||
| 260 | default: size = "Large"; break; | ||
| 231 | case 0: size = "small"; break; | ||
| 232 | case 1: size = "medium"; break; | ||
| 233 | default: size = "large"; break; | ||
| 261 | 234 | } | |
| 262 | size += "Image"; | ||
| 263 | |||
| 264 | while( !it.isNull() ) | ||
| 235 | QString coverUrl; | ||
| 236 | for( int i = 0; i < list.count(); i++ ) | ||
| 265 | 237 | { | |
| 266 | if( it.isElement() ) | ||
| 238 | QDomNode n = list.item( i ); | ||
| 239 | if( n.nodeName() == "image" ) | ||
| 267 | 240 | { | |
| 268 | QDomElement e = it.toElement(); | ||
| 269 | if( e.tagName() == "ASIN" ) | ||
| 270 | { | ||
| 271 | m_asin = e.text(); | ||
| 272 | m_coverAsins += m_asin; | ||
| 273 | } | ||
| 274 | else if( e.tagName() == "DetailPageURL" ) | ||
| 275 | { | ||
| 276 | m_amazonURL = e.text(); | ||
| 277 | m_coverAmazonUrls += m_amazonURL; | ||
| 278 | } | ||
| 279 | else if( e.tagName() == size ) | ||
| 280 | { | ||
| 281 | QDomNode subIt = e.firstChild(); | ||
| 282 | while( !subIt.isNull() ) | ||
| 283 | { | ||
| 284 | if( subIt.isElement() ) | ||
| 285 | { | ||
| 286 | QDomElement subE = subIt.toElement(); | ||
| 287 | if( subE.tagName() == "URL" ) | ||
| 288 | { | ||
| 289 | const QString coverUrl = subE.text(); | ||
| 290 | m_coverUrls += coverUrl; | ||
| 291 | break; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | subIt = subIt.nextSibling(); | ||
| 295 | } | ||
| 296 | } | ||
| 297 | else if( e.tagName() == "ItemAttributes" ) | ||
| 298 | { | ||
| 299 | QDomNodeList nodes = e.childNodes(); | ||
| 300 | QDomNode iter; | ||
| 301 | QString artist; | ||
| 302 | QString album; | ||
| 303 | for( int i = 0; i < nodes.count(); i++ ) | ||
| 304 | { | ||
| 305 | iter = nodes.item( i ); | ||
| 241 | const QDomNode node = list.item( i ); | ||
| 306 | 242 | ||
| 307 | if( iter.isElement() ) | ||
| 308 | { | ||
| 309 | if( iter.nodeName() == "Artist" ) | ||
| 310 | { | ||
| 311 | artist = iter.toElement().text(); | ||
| 312 | } | ||
| 313 | else if( iter.nodeName() == "Title" ) | ||
| 314 | { | ||
| 315 | album = iter.toElement().text(); | ||
| 316 | } | ||
| 317 | } | ||
| 243 | if ( node.hasAttributes() ) { | ||
| 244 | const QString imageSize = node.attributes().namedItem( "size" ).nodeValue(); | ||
| 245 | if ( imageSize == size && node.isElement() ) { | ||
| 246 | coverUrl = node.toElement().text(); | ||
| 318 | 247 | } | |
| 319 | m_coverNames += QString( artist + " - " + album ); | ||
| 320 | 248 | } | |
| 321 | 249 | } | |
| 322 | it = it.nextSibling(); | ||
| 323 | 250 | } | |
| 251 | |||
| 252 | if ( coverUrl.isEmpty() ) return; | ||
| 253 | |||
| 254 | KJob* getJob = KIO::storedGet( KUrl(coverUrl), KIO::NoReload, KIO::HideProgressInfo ); | ||
| 255 | connect( getJob, SIGNAL( result( KJob* ) ), SLOT( finishedImageFetch( KJob* ) ) ); | ||
| 324 | 256 | } | |
| 325 | 257 | ||
| 326 | 258 | void | |
| 327 | 259 | CoverFetcher::finishedImageFetch( KJob *job ) //SLOT | |
| 328 | 260 | { | |
| 329 | if( job->error() ) | ||
| 261 | if( job->error() || !m_pixmap.loadFromData( static_cast<KIO::StoredTransferJob*>( job )->data() ) ) | ||
| 330 | 262 | { | |
| 331 | 263 | debug() << "finishedImageFetch(): KIO::error(): " << job->error(); | |
| 332 | m_errors += i18n("The cover could not be retrieved."); | ||
| 333 | attemptAnotherFetch(); | ||
| 264 | m_errors += i18n( "The cover could not be retrieved." ); | ||
| 334 | 265 | return; | |
| 335 | 266 | } | |
| 336 | 267 | ||
| 337 | if( !m_pixmap.loadFromData( static_cast<KIO::StoredTransferJob*>( job )->data() ) || m_pixmap.width() <= 1 ) | ||
| 338 | { | ||
| 339 | //Amazon seems to offer images of size 1x1 sometimes | ||
| 340 | //Amazon has nothing to offer us for the requested image size | ||
| 341 | m_errors += i18n("The cover-data produced an invalid image."); | ||
| 342 | attemptAnotherFetch(); | ||
| 343 | } | ||
| 344 | |||
| 345 | 268 | else if( m_userCanEditQuery ) | |
| 346 | 269 | { | |
| 347 | 270 | //yay! image found :) | |
| … | … | ||
| 278 | 278 | The::statusBar()->endProgressOperation( job ); //just to be safe... | |
| 279 | 279 | } | |
| 280 | 280 | ||
| 281 | |||
| 282 | void | ||
| 283 | CoverFetcher::attemptAnotherFetch() | ||
| 284 | { | ||
| 285 | |||
| 286 | if( !m_coverUrls.isEmpty() ) | ||
| 287 | { | ||
| 288 | // Amazon suggested some more cover URLs to try before we | ||
| 289 | // try a different query | ||
| 290 | KJob* job = KIO::storedGet( KUrl(m_coverUrls.front()), KIO::NoReload, KIO::HideProgressInfo ); | ||
| 291 | connect( job, SIGNAL(result( KJob* )), SLOT(finishedImageFetch( KJob* )) ); | ||
| 292 | |||
| 293 | if( m_userCanEditQuery ) | ||
| 294 | The::statusBar()->newProgressOperation( job, i18n( "Fetching Cover" ) ); | ||
| 295 | |||
| 296 | m_coverUrls.pop_front(); | ||
| 297 | |||
| 298 | m_currentCoverName = m_coverNames.front(); | ||
| 299 | m_coverNames.pop_front(); | ||
| 300 | |||
| 301 | m_amazonURL = m_coverAmazonUrls.front(); | ||
| 302 | m_coverAmazonUrls.pop_front(); | ||
| 303 | |||
| 304 | m_asin = m_coverAsins.front(); | ||
| 305 | m_coverAsins.pop_front(); | ||
| 306 | } | ||
| 307 | |||
| 308 | else if( !m_xml.isEmpty() && m_size > 0 ) | ||
| 309 | { | ||
| 310 | // we need to try smaller sizes, this often is | ||
| 311 | // fruitless, but does work out sometimes. | ||
| 312 | m_size--; | ||
| 313 | |||
| 314 | finishedXmlFetch( 0 ); | ||
| 315 | } | ||
| 316 | |||
| 317 | else if( !m_queries.isEmpty() ) | ||
| 318 | { | ||
| 319 | // we have some queries left in the pot | ||
| 320 | startFetch( m_albumPtr ); | ||
| 321 | } | ||
| 322 | else if( m_userCanEditQuery ) | ||
| 323 | { | ||
| 324 | // we have exhausted all the predetermined queries | ||
| 325 | // so lets let the user give it a try | ||
| 326 | getUserQuery( i18n("You have seen all the covers Amazon returned using the query below. Perhaps you can refine it:") ); | ||
| 327 | m_coverAmazonUrls.clear(); | ||
| 328 | m_coverAsins.clear(); | ||
| 329 | m_coverUrls.clear(); | ||
| 330 | m_coverNames.clear(); | ||
| 331 | } | ||
| 332 | else | ||
| 333 | { | ||
| 334 | m_isFetching = false; | ||
| 335 | finishWithError( i18n("No cover found") ); | ||
| 336 | } | ||
| 337 | } | ||
| 338 | |||
| 339 | |||
| 340 | // Moved outside the only function that uses it because | ||
| 341 | // gcc 2.95 doesn't like class declarations there. | ||
| 342 | class EditSearchDialog : public QDialog, public Ui::EditCoverSearchDialog | ||
| 343 | { | ||
| 344 | public: | ||
| 345 | EditSearchDialog( QWidget* parent, const QString &text, const QString &keyword, CoverFetcher *fetcher ) | ||
| 346 | : QDialog( parent ) | ||
| 347 | { | ||
| 348 | setupUi( this ); | ||
| 349 | setWindowTitle( i18n( "Amazon Query Editor" ) ); | ||
| 350 | textLabel->setText( text ); | ||
| 351 | SearchLineEdit->setText( keyword ); | ||
| 352 | |||
| 353 | if( CoverManager::instance() ) | ||
| 354 | connect( amazonLocale, SIGNAL( activated(int) ), | ||
| 355 | CoverManager::instance(), SLOT( changeLocale(int) ) ); | ||
| 356 | else | ||
| 357 | connect( amazonLocale, SIGNAL( activated(int) ), | ||
| 358 | fetcher, SLOT( changeLocale(int) ) ); | ||
| 359 | |||
| 360 | int currentLocale = CoverFetcher::localeStringToID( AmarokConfig::amazonLocale() ); | ||
| 361 | amazonLocale->setCurrentIndex( currentLocale ); | ||
| 362 | |||
| 363 | adjustSize(); | ||
| 364 | setFixedHeight( height() ); | ||
| 365 | } | ||
| 366 | |||
| 367 | QString query() { return SearchLineEdit->text(); } | ||
| 368 | }; | ||
| 369 | |||
| 370 | QString | ||
| 371 | CoverFetcher::localeIDToString( int id )//static | ||
| 372 | { | ||
| 373 | switch ( id ) | ||
| 374 | { | ||
| 375 | case International: | ||
| 376 | return "us"; | ||
| 377 | case Canada: | ||
| 378 | return "ca"; | ||
| 379 | case France: | ||
| 380 | return "fr"; | ||
| 381 | case Germany: | ||
| 382 | return "de"; | ||
| 383 | case Japan: | ||
| 384 | return "jp"; | ||
| 385 | case UK: | ||
| 386 | return "uk"; | ||
| 387 | } | ||
| 388 | |||
| 389 | return "us"; | ||
| 390 | } | ||
| 391 | |||
| 392 | int | ||
| 393 | CoverFetcher::localeStringToID( const QString &s ) | ||
| 394 | { | ||
| 395 | int id = International; | ||
| 396 | if( s == "fr" ) id = France; | ||
| 397 | else if( s == "de" ) id = Germany; | ||
| 398 | else if( s == "jp" ) id = Japan; | ||
| 399 | else if( s == "uk" ) id = UK; | ||
| 400 | else if( s == "ca" ) id = Canada; | ||
| 401 | |||
| 402 | return id; | ||
| 403 | } | ||
| 404 | |||
| 405 | void | ||
| 406 | CoverFetcher::changeLocale( int id )//SLOT | ||
| 407 | { | ||
| 408 | QString locale = localeIDToString( id ); | ||
| 409 | AmarokConfig::setAmazonLocale( locale ); | ||
| 410 | } | ||
| 411 | |||
| 412 | void | ||
| 413 | CoverFetcher::getUserQuery( QString explanation ) | ||
| 414 | { | ||
| 415 | if( explanation.isEmpty() ) | ||
| 416 | explanation = i18n("Ask Amazon for covers using this query:"); | ||
| 417 | |||
| 418 | EditSearchDialog dialog( | ||
| 419 | static_cast<QWidget*>( parent() ), | ||
| 420 | explanation, | ||
| 421 | m_userQuery, | ||
| 422 | this ); | ||
| 423 | |||
| 424 | |||
| 425 | switch( dialog.exec() ) | ||
| 426 | { | ||
| 427 | case QDialog::Accepted: | ||
| 428 | m_userQuery = dialog.query(); | ||
| 429 | debug() << m_userQuery; | ||
| 430 | m_queries.clear(); | ||
| 431 | m_queries << m_userQuery; | ||
| 432 | startFetch( m_albumPtr ); | ||
| 433 | break; | ||
| 434 | case QDialog::Rejected: | ||
| 435 | break; | ||
| 436 | default: | ||
| 437 | finishWithError( i18n( "Aborted." ) ); | ||
| 438 | break; | ||
| 439 | } | ||
| 440 | } | ||
| 441 | |||
| 442 | 281 | class CoverFoundDialog : public KDialog | |
| 443 | 282 | { | |
| 444 | 283 | public: | |
| … | … | ||
| 293 | 293 | QLabel *labelName = new QLabel( box ); | |
| 294 | 294 | KHBox *buttons = new KHBox( box ); | |
| 295 | 295 | KPushButton *save = new KPushButton( KStandardGuiItem::save(), buttons ); | |
| 296 | KPushButton *newsearch = new KPushButton( i18n( "Ne&w Search..." ), buttons ); | ||
| 297 | newsearch->setObjectName( "NewSearch" ); | ||
| 298 | KPushButton *nextcover = new KPushButton( i18n( "&Next Cover" ), buttons ); | ||
| 299 | nextcover->setObjectName( "NextCover" ); | ||
| 300 | 296 | KPushButton *cancel = new KPushButton( KStandardGuiItem::cancel(), buttons ); | |
| 301 | 297 | ||
| 302 | 298 | labelPix ->setAlignment( Qt::AlignHCenter ); | |
| … | … | ||
| 305 | 305 | this->setCaption( i18n("Cover Found") ); | |
| 306 | 306 | ||
| 307 | 307 | connect( save, SIGNAL(clicked()), SLOT(accept()) ); | |
| 308 | connect( newsearch, SIGNAL(clicked()), SLOT(accept()) ); | ||
| 309 | connect( nextcover, SIGNAL(clicked()), SLOT(accept()) ); | ||
| 310 | 308 | connect( cancel, SIGNAL(clicked()), SLOT(reject()) ); | |
| 311 | 309 | } | |
| 312 | 310 | ||
| … | … | ||
| 333 | 333 | case KDialog::Rejected: //make sure we do not show any more dialogs | |
| 334 | 334 | debug() << "cover rejected"; | |
| 335 | 335 | break; | |
| 336 | case 1000: //showQueryEditor() | ||
| 337 | getUserQuery(); | ||
| 338 | m_coverAmazonUrls.clear(); | ||
| 339 | m_coverAsins.clear(); | ||
| 340 | m_coverUrls.clear(); | ||
| 341 | m_coverNames.clear(); | ||
| 342 | break; | ||
| 343 | case 1001: //nextCover() | ||
| 344 | attemptAnotherFetch(); | ||
| 345 | break; | ||
| 346 | 336 | default: | |
| 347 | 337 | finishWithError( i18n( "Aborted." ) ); | |
| 348 | 338 | break; | |
| … | … | ||
| 347 | 347 | m_albumPtr->setImage( image() ); | |
| 348 | 348 | m_isFetching = false; | |
| 349 | 349 | if( !m_userCanEditQuery /*manual fetch*/ && !m_albums.isEmpty() ) | |
| 350 | buildQueries( m_albums.takeFirst() ); | ||
| 350 | startFetch( m_albums.takeFirst() ); | ||
| 351 | |||
| 351 | 352 | } | |
| 352 | 353 | ||
| 353 | 354 | void | |
| … | … | ||
| 368 | 368 | if( !m_albums.isEmpty() ) | |
| 369 | 369 | { | |
| 370 | 370 | debug() << "next album" << m_albums[0]->name(); | |
| 371 | buildQueries( m_albums.takeFirst() ); | ||
| 371 | startFetch( m_albums.takeFirst() ); | ||
| 372 | 372 | } | |
| 373 | |||
| 373 | 374 | } | |
| 374 | 375 | ||
| 375 | 376 | #include "CoverFetcher.moc" |
src/covermanager/CoverFetcher.h
(1 / 20)
|   | |||
| 2 | 2 | * Copyright (c) 2004 Mark Kretschmann <kretschmann@kde.org> * | |
| 3 | 3 | * Copyright (c) 2004 Stefan Bogner <bochi@online.ms> * | |
| 4 | 4 | * Copyright (c) 2007 Dan Meltzer <parallelgrapefruit@gmail.com> * | |
| 5 | * Copyright (c) 2009 Martin Sandsmark <sandsmark@samfundet.no> * | ||
| 5 | 6 | * * | |
| 6 | 7 | * This program is free software; you can redistribute it and/or modify it under * | |
| 7 | 8 | * the terms of the GNU General Public License as published by the Free Software * | |
| … | … | ||
| 72 | 72 | /// Main Fetch loop | |
| 73 | 73 | AMAROK_EXPORT void manualFetch( Meta::AlbumPtr album ); | |
| 74 | 74 | ||
| 75 | QString amazonURL() const { return m_amazonURL; } | ||
| 76 | QString asin() const { return m_asin; } | ||
| 77 | 75 | QPixmap image() const { return m_pixmap; } | |
| 78 | 76 | ||
| 79 | 77 | AMAROK_EXPORT void queueAlbum( Meta::AlbumPtr album ); | |
| … | … | ||
| 80 | 80 | bool wasError() const { return !m_success; } | |
| 81 | 81 | QStringList errors() const { return m_errors; } | |
| 82 | 82 | ||
| 83 | enum Locale { International = 0, Canada, France, Germany, Japan, UK }; | ||
| 84 | static QString localeIDToString( int id ); | ||
| 85 | static int localeStringToID( const QString &locale ); | ||
| 86 | |||
| 87 | 83 | private slots: | |
| 88 | 84 | void finishedXmlFetch( KJob * job ); | |
| 89 | 85 | void finishedImageFetch( KJob * job ); | |
| 90 | void changeLocale( int id ); | ||
| 91 | 86 | ||
| 92 | 87 | private: | |
| 93 | 88 | static CoverFetcher* s_instance; | |
| … | … | ||
| 100 | 100 | QString m_userQuery; /// the query from the query edit dialog | |
| 101 | 101 | QString m_xml; | |
| 102 | 102 | QPixmap m_pixmap; | |
| 103 | QString m_amazonURL; | ||
| 104 | 103 | QString m_asin; | |
| 105 | 104 | int m_size; | |
| 106 | 105 | ||
| 107 | 106 | QStringList m_queries; | |
| 108 | QStringList m_coverAsins; | ||
| 109 | QStringList m_coverAmazonUrls; | ||
| 110 | QStringList m_coverUrls; | ||
| 111 | QStringList m_coverNames; | ||
| 112 | 107 | QString m_currentCoverName; | |
| 113 | 108 | QStringList m_errors; | |
| 114 | 109 | ||
| … | … | ||
| 111 | 111 | bool m_isFetching; | |
| 112 | 112 | ||
| 113 | 113 | private: | |
| 114 | void buildQueries( Meta::AlbumPtr album ); | ||
| 115 | |||
| 116 | 114 | /// Fetch a cover | |
| 117 | 115 | void startFetch( Meta::AlbumPtr album ); | |
| 118 | 116 | ||
| … | … | ||
| 119 | 119 | ||
| 120 | 120 | /// The fetch failed, finish up and log an error message | |
| 121 | 121 | void finishWithError( const QString &message, KJob *job = 0 ); | |
| 122 | |||
| 123 | /// Prompt the user for a query | ||
| 124 | void getUserQuery( QString explanation = QString() ); | ||
| 125 | |||
| 126 | /// Will try all available queries, and then prompt the user, if allowed | ||
| 127 | void attemptAnotherFetch(); | ||
| 128 | 122 | ||
| 129 | 123 | /// Show the cover that has been found | |
| 130 | 124 | void showCover(); |
|   | |||
| 194 | 194 | viewGroup->addAction( m_selectAlbumsWithoutCover ); | |
| 195 | 195 | m_selectAllAlbums->setChecked( true ); | |
| 196 | 196 | ||
| 197 | // amazon locale menu | ||
| 198 | QString locale = AmarokConfig::amazonLocale(); | ||
| 199 | m_currentLocale = CoverFetcher::localeStringToID( locale ); | ||
| 200 | |||
| 201 | QAction *a; | ||
| 202 | QActionGroup *localeGroup = new QActionGroup( this ); | ||
| 203 | localeGroup->setExclusive( true ); | ||
| 204 | |||
| 205 | m_amazonLocaleMenu = new KMenu( this ); | ||
| 206 | |||
| 207 | a = m_amazonLocaleMenu->addAction( i18nc( "The locale to use when fetching covers from amazon.com", "International"), this, SLOT( slotSetLocaleIntl() ) ); | ||
| 208 | if( m_currentLocale == CoverFetcher::International ) a->setChecked( true ); | ||
| 209 | localeGroup->addAction( a ); | ||
| 210 | |||
| 211 | a = m_amazonLocaleMenu->addAction( i18n("Canada"), this, SLOT( slotSetLocaleCa() ) ); | ||
| 212 | if( m_currentLocale == CoverFetcher::Canada ) a->setChecked( true ); | ||
| 213 | localeGroup->addAction( a ); | ||
| 214 | |||
| 215 | a = m_amazonLocaleMenu->addAction( i18n("France"), this, SLOT( slotSetLocaleFr() ) ); | ||
| 216 | if( m_currentLocale == CoverFetcher::France ) a->setChecked( true ); | ||
| 217 | localeGroup->addAction( a ); | ||
| 218 | |||
| 219 | a = m_amazonLocaleMenu->addAction( i18n("Germany"), this, SLOT( slotSetLocaleDe() ) ); | ||
| 220 | if( m_currentLocale == CoverFetcher::Germany ) a->setChecked( true ); | ||
| 221 | localeGroup->addAction( a ); | ||
| 222 | |||
| 223 | a = m_amazonLocaleMenu->addAction( i18n("Japan"), this, SLOT( slotSetLocaleJp() ) ); | ||
| 224 | if( m_currentLocale == CoverFetcher::Japan ) a->setChecked( true ); | ||
| 225 | localeGroup->addAction( a ); | ||
| 226 | |||
| 227 | a = m_amazonLocaleMenu->addAction( i18n("United Kingdom"), this, SLOT( slotSetLocaleUk() ) ); | ||
| 228 | if( m_currentLocale == CoverFetcher::UK ) a->setChecked( true ); | ||
| 229 | localeGroup->addAction( a ); | ||
| 230 | |||
| 231 | KToolBar* toolBar = new KToolBar( hbox ); | ||
| 232 | toolBar->setToolButtonStyle( Qt::ToolButtonTextBesideIcon ); | ||
| 233 | { | ||
| 234 | QAction* viewMenuAction = new QAction( KIcon( "view-list-icons" ), i18nc( "@title buttontext for popup-menu", "View" ), this ); | ||
| 235 | viewMenuAction->setMenu( m_viewMenu ); | ||
| 236 | toolBar->addAction( viewMenuAction ); | ||
| 237 | } | ||
| 238 | { | ||
| 239 | QAction* localeMenuAction = new QAction( KIcon( "preferences-desktop-locale-amarok" ), i18n( "Amazon Locale" ), this ); | ||
| 240 | localeMenuAction->setMenu( m_amazonLocaleMenu ); | ||
| 241 | toolBar->addAction( localeMenuAction ); | ||
| 242 | } | ||
| 243 | |||
| 244 | 197 | //fetch missing covers button | |
| 245 | 198 | m_fetchButton = new KPushButton( KGuiItem( i18n("Fetch Missing Covers"), "get-hot-new-stuff-amarok" ), hbox ); | |
| 246 | 199 | connect( m_fetchButton, SIGNAL(clicked()), SLOT(fetchMissingCovers()) ); | |
| … | … | ||
| 287 | 287 | dialog->show(); | |
| 288 | 288 | } | |
| 289 | 289 | ||
| 290 | |||
| 291 | QString CoverManager::amazonTld() //static | ||
| 292 | { | ||
| 293 | if( AmarokConfig::amazonLocale() == "us" ) | ||
| 294 | return "com"; | ||
| 295 | else if( AmarokConfig::amazonLocale()== "jp" ) | ||
| 296 | return "jp"; | ||
| 297 | else if( AmarokConfig::amazonLocale() == "uk" ) | ||
| 298 | return "co.uk"; | ||
| 299 | else if( AmarokConfig::amazonLocale() == "ca" ) | ||
| 300 | return "ca"; | ||
| 301 | else | ||
| 302 | return AmarokConfig::amazonLocale(); | ||
| 303 | } | ||
| 304 | |||
| 305 | 290 | void | |
| 306 | 291 | CoverManager::metadataChanged( Meta::AlbumPtr album ) | |
| 307 | 292 | { | |
| … | … | ||
| 540 | 540 | } | |
| 541 | 541 | m_currentView = id; | |
| 542 | 542 | } | |
| 543 | |||
| 544 | void CoverManager::changeLocale( int id ) //SLOT | ||
| 545 | { | ||
| 546 | QString locale = CoverFetcher::localeIDToString( id ); | ||
| 547 | AmarokConfig::setAmazonLocale( locale ); | ||
| 548 | m_currentLocale = id; | ||
| 549 | } | ||
| 550 | |||
| 551 | 543 | ||
| 552 | 544 | void CoverManager::coverFetched( const QString &artist, const QString &album ) //SLOT | |
| 553 | 545 | { |
src/covermanager/CoverManager.h
(0 / 14)
|   | |||
| 62 | 62 | ||
| 63 | 63 | void setStatusText( QString text ); | |
| 64 | 64 | ||
| 65 | // Return the top level domain for the current locale | ||
| 66 | static QString amazonTld(); | ||
| 67 | |||
| 68 | 65 | // Reimplemented from Meta::Observer | |
| 69 | 66 | using Observer::metadataChanged; | |
| 70 | 67 | void metadataChanged( Meta::AlbumPtr album ); | |
| 71 | 68 | ||
| 72 | 69 | public slots: | |
| 73 | 70 | void updateStatusBar(); | |
| 74 | void changeLocale( int id ); | ||
| 75 | 71 | ||
| 76 | 72 | private slots: | |
| 77 | 73 | void slotArtistQueryResult( QString collectionId, Meta::ArtistList artists ); | |
| … | … | ||
| 86 | 86 | void slotShowAlbumsWithCover() { changeView( AlbumsWithCover ); } | |
| 87 | 87 | void slotShowAlbumsWithoutCover() { changeView( AlbumsWithoutCover ); } | |
| 88 | 88 | void changeView( int id ); | |
| 89 | |||
| 90 | void slotSetLocaleIntl() { changeLocale( CoverFetcher::International ); } | ||
| 91 | void slotSetLocaleCa() { changeLocale( CoverFetcher::Canada ); } | ||
| 92 | void slotSetLocaleDe() { changeLocale( CoverFetcher::Germany ); } | ||
| 93 | void slotSetLocaleFr() { changeLocale( CoverFetcher::France ); } | ||
| 94 | void slotSetLocaleJp() { changeLocale( CoverFetcher::Japan ); } | ||
| 95 | void slotSetLocaleUk() { changeLocale( CoverFetcher::UK ); } | ||
| 96 | 89 | ||
| 97 | 90 | void fetchMissingCovers(); | |
| 98 | 91 | void coverFetched( const QString&, const QString& ); | |
| … | … | ||
| 105 | 105 | CoverView *m_coverView; | |
| 106 | 106 | Amarok::LineEdit *m_searchEdit; | |
| 107 | 107 | KPushButton *m_fetchButton; | |
| 108 | KMenu *m_amazonLocaleMenu; | ||
| 109 | 108 | KMenu *m_viewMenu; | |
| 110 | QToolButton *m_amazonLocaleButton; | ||
| 111 | 109 | QToolButton *m_viewButton; | |
| 112 | int m_currentLocale; | ||
| 113 | 110 | int m_currentView; | |
| 114 | 111 | ||
| 115 | 112 | Meta::ArtistList m_artistList; |

