/src/libtomahawk/Result.cpp

http://github.com/tomahawk-player/tomahawk · C++ · 714 lines · 518 code · 175 blank · 21 comment · 32 complexity · 81013e87e1541ffe2678bdb0d9552ed8 MD5 · raw file

  1. /* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2. *
  3. * Copyright 2010-2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4. * Copyright 2015, Dominik Schmidt <domme@tomahawk-player.org>
  5. *
  6. * Tomahawk is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Tomahawk is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "Result.h"
  20. #include "collection/Collection.h"
  21. #include "database/Database.h"
  22. #include "filemetadata/MetadataEditor.h"
  23. #include "resolvers/ExternalResolverGui.h"
  24. #include "resolvers/Resolver.h"
  25. #include "utils/TomahawkUtilsGui.h"
  26. #include "utils/Logger.h"
  27. #include "Album.h"
  28. #include "Pipeline.h"
  29. #include "PlaylistInterface.h"
  30. #include "Source.h"
  31. #include "TomahawkSettings.h"
  32. #include "Track.h"
  33. #include "Typedefs.h"
  34. #include <QCoreApplication>
  35. using namespace Tomahawk;
  36. static QHash< QString, result_wptr > s_results;
  37. static QMutex s_mutex;
  38. typedef QMap< QString, QPixmap > SourceIconCache;
  39. Q_GLOBAL_STATIC( SourceIconCache, sourceIconCache );
  40. static QMutex s_sourceIconMutex;
  41. inline QString
  42. sourceCacheKey( Resolver* resolver, const QSize& size, TomahawkUtils::ImageMode style )
  43. {
  44. QString str;
  45. QTextStream stream( &str );
  46. stream << resolver << size.width() << size.height() << "_" << style;
  47. return str;
  48. }
  49. Tomahawk::result_ptr
  50. Result::get( const QString& url, const track_ptr& track )
  51. {
  52. if ( url.trimmed().isEmpty() || track.isNull() )
  53. {
  54. return result_ptr();
  55. }
  56. QMutexLocker lock( &s_mutex );
  57. if ( s_results.contains( url ) )
  58. {
  59. return s_results.value( url );
  60. }
  61. result_ptr r = result_ptr( new Result( url, track ), &Result::deleteLater );
  62. r->moveToThread( QCoreApplication::instance()->thread() );
  63. r->setWeakRef( r.toWeakRef() );
  64. s_results.insert( url, r );
  65. return r;
  66. }
  67. result_ptr
  68. Result::getCached( const QString& url )
  69. {
  70. if ( url.trimmed().isEmpty() )
  71. {
  72. return result_ptr();
  73. }
  74. QMutexLocker lock( &s_mutex );
  75. if ( s_results.contains( url ) )
  76. {
  77. return s_results.value( url );
  78. }
  79. return result_ptr();
  80. }
  81. Result::Result( const QString& url, const track_ptr& track )
  82. : QObject()
  83. , m_url( url )
  84. , m_isPreview( false )
  85. , m_checked( false )
  86. , m_bitrate( 0 )
  87. , m_size( 0 )
  88. , m_modtime( 0 )
  89. , m_fileId( 0 )
  90. , m_track( track )
  91. {
  92. connect( Pipeline::instance(), SIGNAL( resolverRemoved( Tomahawk::Resolver* ) ), SLOT( onResolverRemoved( Tomahawk::Resolver* ) ), Qt::QueuedConnection );
  93. }
  94. Result::~Result()
  95. {
  96. tDebug( LOGVERBOSE ) << Q_FUNC_INFO << toString();
  97. }
  98. void
  99. Result::deleteLater()
  100. {
  101. QMutexLocker lock( &s_mutex );
  102. if ( s_results.contains( m_url ) )
  103. {
  104. s_results.remove( m_url );
  105. }
  106. QObject::deleteLater();
  107. }
  108. void
  109. Result::onResolverRemoved( Tomahawk::Resolver* resolver )
  110. {
  111. m_mutex.lock();
  112. if ( m_resolver.data() == resolver )
  113. {
  114. m_resolver = 0;
  115. m_mutex.unlock();
  116. emit statusChanged();
  117. }
  118. else
  119. {
  120. m_mutex.unlock();
  121. }
  122. }
  123. collection_ptr
  124. Result::resolvedByCollection() const
  125. {
  126. return m_collection;
  127. }
  128. QString
  129. Result::url() const
  130. {
  131. QMutexLocker lock( &m_mutex );
  132. return m_url;
  133. }
  134. bool
  135. Result::checked() const
  136. {
  137. QMutexLocker lock( &m_mutex );
  138. return m_checked;
  139. }
  140. bool
  141. Result::isPreview() const
  142. {
  143. QMutexLocker lock( &m_mutex );
  144. return m_isPreview;
  145. }
  146. QString
  147. Result::mimetype() const
  148. {
  149. QMutexLocker lock( &m_mutex );
  150. return m_mimetype;
  151. }
  152. RID
  153. Result::id() const
  154. {
  155. QMutexLocker lock( &m_mutex );
  156. if ( m_rid.isEmpty() )
  157. m_rid = uuid();
  158. return m_rid;
  159. }
  160. bool
  161. Result::isOnline() const
  162. {
  163. if ( !resolvedByCollection().isNull() )
  164. {
  165. return resolvedByCollection()->isOnline();
  166. }
  167. else
  168. {
  169. QMutexLocker lock( &m_mutex );
  170. return !m_resolver.isNull();
  171. }
  172. }
  173. bool
  174. Result::playable() const
  175. {
  176. if ( resolvedByCollection() )
  177. {
  178. return resolvedByCollection()->isOnline();
  179. }
  180. return true;
  181. }
  182. bool
  183. Result::isLocal() const
  184. {
  185. return resolvedByCollection().isNull() ? false : resolvedByCollection()->isLocal();
  186. }
  187. QVariant
  188. Result::toVariant() const
  189. {
  190. track_ptr t = track();
  191. QVariantMap m;
  192. m.insert( "artist", t->artist() );
  193. m.insert( "album", t->album() );
  194. m.insert( "track", t->track() );
  195. m.insert( "source", friendlySource() );
  196. m.insert( "mimetype", mimetype() );
  197. m.insert( "size", size() );
  198. m.insert( "bitrate", bitrate() );
  199. m.insert( "duration", t->duration() );
  200. // m.insert( "score", score() );
  201. m.insert( "sid", id() );
  202. m.insert( "discnumber", t->discnumber() );
  203. m.insert( "albumpos", t->albumpos() );
  204. m.insert( "preview", isPreview() );
  205. m.insert( "purchaseUrl", purchaseUrl() );
  206. if ( !t->composer().isEmpty() )
  207. m.insert( "composer", t->composer() );
  208. return m;
  209. }
  210. QString
  211. Result::toString() const
  212. {
  213. m_mutex.lock();
  214. track_ptr track = m_track;
  215. QString url = m_url;
  216. m_mutex.unlock();
  217. if ( track )
  218. {
  219. return QString( "Result(%1) %2 - %3%4 (%5)" )
  220. .arg( id() )
  221. .arg( track->artist() )
  222. .arg( track->track() )
  223. .arg( track->album().isEmpty() ? QString() : QString( " on %1" ).arg( track->album() ) )
  224. .arg( url );
  225. }
  226. else
  227. {
  228. return QString( "Result(%1) (%2)" )
  229. .arg( id() )
  230. .arg( url );
  231. }
  232. }
  233. Tomahawk::query_ptr
  234. Result::toQuery()
  235. {
  236. QMutexLocker l( &m_mutex );
  237. if ( m_query.isNull() )
  238. {
  239. query_ptr query = Tomahawk::Query::get( m_track );
  240. if ( !query )
  241. return query_ptr();
  242. m_query = query->weakRef();
  243. QList<Tomahawk::result_ptr> rl;
  244. rl << m_ownRef.toStrongRef();
  245. m_mutex.unlock();
  246. query->addResults( rl );
  247. m_mutex.lock();
  248. query->setResolveFinished( true );
  249. return query;
  250. }
  251. return m_query.toStrongRef();
  252. }
  253. void
  254. Result::onOnline()
  255. {
  256. emit statusChanged();
  257. }
  258. void
  259. Result::onOffline()
  260. {
  261. emit statusChanged();
  262. }
  263. void
  264. Result::setResolvedByCollection( const Tomahawk::collection_ptr& collection, bool emitOnlineEvents )
  265. {
  266. m_collection = collection;
  267. if ( emitOnlineEvents )
  268. {
  269. Q_ASSERT( !collection.isNull() );
  270. connect( collection.data(), SIGNAL( destroyed( QObject * ) ), SLOT( onOffline() ), Qt::QueuedConnection );
  271. connect( collection.data(), SIGNAL( online() ), SLOT( onOnline() ), Qt::QueuedConnection );
  272. connect( collection.data(), SIGNAL( offline() ), SLOT( onOffline() ), Qt::QueuedConnection );
  273. }
  274. }
  275. void
  276. Result::setFriendlySource( const QString& s )
  277. {
  278. QMutexLocker lock( &m_mutex );
  279. m_friendlySource = s;
  280. }
  281. void
  282. Result::setPreview( bool isPreview )
  283. {
  284. QMutexLocker lock( &m_mutex );
  285. m_isPreview = isPreview;
  286. }
  287. void
  288. Result::setPurchaseUrl( const QString& u )
  289. {
  290. QMutexLocker lock( &m_mutex );
  291. m_purchaseUrl = u;
  292. }
  293. void
  294. Result::setLinkUrl( const QString& u )
  295. {
  296. QMutexLocker lock( &m_mutex );
  297. m_linkUrl = u;
  298. }
  299. void
  300. Result::setChecked( bool checked )
  301. {
  302. QMutexLocker lock( &m_mutex );
  303. m_checked = checked;
  304. }
  305. void
  306. Result::setMimetype( const QString& mimetype )
  307. {
  308. QMutexLocker lock( &m_mutex );
  309. m_mimetype = mimetype;
  310. }
  311. void
  312. Result::setBitrate( unsigned int bitrate )
  313. {
  314. QMutexLocker lock( &m_mutex );
  315. m_bitrate = bitrate;
  316. }
  317. void
  318. Result::setSize( unsigned int size )
  319. {
  320. QMutexLocker lock( &m_mutex );
  321. m_size = size;
  322. }
  323. void
  324. Result::setModificationTime( unsigned int modtime )
  325. {
  326. QMutexLocker lock( &m_mutex );
  327. m_modtime = modtime;
  328. }
  329. void
  330. Result::setTrack( const track_ptr& track )
  331. {
  332. QMutexLocker lock( &m_mutex );
  333. m_track = track;
  334. }
  335. unsigned int
  336. Result::fileId() const
  337. {
  338. QMutexLocker lock( &m_mutex );
  339. return m_fileId;
  340. }
  341. QString
  342. Result::friendlySource() const
  343. {
  344. if ( resolvedByCollection().isNull() )
  345. {
  346. QMutexLocker lock( &m_mutex );
  347. return m_friendlySource;
  348. }
  349. else
  350. return resolvedByCollection()->prettyName();
  351. }
  352. QString
  353. Result::purchaseUrl() const
  354. {
  355. QMutexLocker lock( &m_mutex );
  356. return m_purchaseUrl;
  357. }
  358. QString
  359. Result::linkUrl() const
  360. {
  361. QMutexLocker lock( &m_mutex );
  362. return m_linkUrl;
  363. }
  364. QPixmap
  365. Result::sourceIcon( TomahawkUtils::ImageMode style, const QSize& desiredSize ) const
  366. {
  367. if ( resolvedByCollection().isNull() )
  368. {
  369. //QMutexLocker lock( &m_mutex );
  370. const ExternalResolver* resolver = qobject_cast< ExternalResolver* >( m_resolver.data() );
  371. if ( !resolver )
  372. {
  373. return QPixmap();
  374. }
  375. else
  376. {
  377. QMutexLocker l( &s_sourceIconMutex );
  378. const QString key = sourceCacheKey( m_resolver.data(), desiredSize, style );
  379. if ( !sourceIconCache()->contains( key ) )
  380. {
  381. QPixmap pixmap = resolver->icon( desiredSize );
  382. if ( pixmap.isNull() )
  383. return pixmap;
  384. switch ( style )
  385. {
  386. case TomahawkUtils::DropShadow:
  387. pixmap = TomahawkUtils::addDropShadow( pixmap, QSize() );
  388. break;
  389. case TomahawkUtils::RoundedCorners:
  390. pixmap = TomahawkUtils::createRoundedImage( pixmap, QSize() );
  391. break;
  392. default:
  393. break;
  394. }
  395. sourceIconCache()->insert( key, pixmap );
  396. return pixmap;
  397. }
  398. else
  399. {
  400. return sourceIconCache()->value( key );
  401. }
  402. }
  403. }
  404. else
  405. {
  406. QPixmap avatar = resolvedByCollection()->icon( desiredSize );
  407. return avatar;
  408. }
  409. }
  410. unsigned int
  411. Result::bitrate() const
  412. {
  413. QMutexLocker lock( &m_mutex );
  414. return m_bitrate;
  415. }
  416. unsigned int
  417. Result::size() const
  418. {
  419. QMutexLocker lock( &m_mutex );
  420. return m_size;
  421. }
  422. unsigned int
  423. Result::modificationTime() const
  424. {
  425. QMutexLocker lock( &m_mutex );
  426. return m_modtime;
  427. }
  428. void
  429. Result::setFileId( unsigned int id )
  430. {
  431. QMutexLocker lock( &m_mutex );
  432. m_fileId = id;
  433. }
  434. Tomahawk::Resolver*
  435. Result::resolvedBy() const
  436. {
  437. QMutexLocker lock( &m_mutex );
  438. if ( !m_collection.isNull() )
  439. return m_collection.data();
  440. return m_resolver.data();
  441. }
  442. void
  443. Result::setResolvedByResolver( Tomahawk::Resolver* resolver )
  444. {
  445. QMutexLocker lock( &m_mutex );
  446. m_resolver = QPointer< Tomahawk::Resolver >( resolver );
  447. }
  448. QPointer< Resolver > Result::resolvedByResolver() const
  449. {
  450. QMutexLocker lock( &m_mutex );
  451. return m_resolver;
  452. }
  453. void
  454. Result::doneEditing()
  455. {
  456. // m_query.clear();
  457. emit updated();
  458. }
  459. track_ptr
  460. Result::track() const
  461. {
  462. QMutexLocker lock( &m_mutex );
  463. return m_track;
  464. }
  465. QList< DownloadFormat >
  466. Result::downloadFormats() const
  467. {
  468. QMutexLocker lock( &m_mutex );
  469. return m_formats;
  470. }
  471. void
  472. Result::setDownloadFormats( const QList<DownloadFormat>& formats )
  473. {
  474. if ( formats.isEmpty() )
  475. return;
  476. QMutexLocker lock( &m_mutex );
  477. m_formats.clear();
  478. foreach ( const DownloadFormat& format, formats )
  479. {
  480. if ( format.extension.toLower() == TomahawkSettings::instance()->downloadsPreferredFormat().toLower() )
  481. {
  482. m_formats.insert( 0, format );
  483. }
  484. else
  485. {
  486. m_formats << format;
  487. }
  488. }
  489. if ( !m_formats.isEmpty() )
  490. {
  491. connect( TomahawkSettings::instance(), SIGNAL( changed() ), this, SLOT( onSettingsChanged() ), Qt::UniqueConnection );
  492. }
  493. else
  494. {
  495. disconnect( TomahawkSettings::instance(), SIGNAL( changed() ), this, SLOT( onSettingsChanged() ) );
  496. }
  497. }
  498. void
  499. Result::onSettingsChanged()
  500. {
  501. if ( TomahawkSettings::instance()->downloadsPreferredFormat().toLower() != downloadFormats().first().extension.toLower() )
  502. {
  503. setDownloadFormats( downloadFormats() );
  504. emit updated();
  505. }
  506. }
  507. downloadjob_ptr
  508. Result::toDownloadJob( const DownloadFormat& format )
  509. {
  510. if ( !m_downloadJob )
  511. {
  512. m_downloadJob = downloadjob_ptr( new DownloadJob( weakRef().toStrongRef(), format ) );
  513. connect( m_downloadJob.data(), SIGNAL( progress( int ) ), SIGNAL( updated() ) );
  514. connect( m_downloadJob.data(), SIGNAL( stateChanged( DownloadJob::TrackState, DownloadJob::TrackState ) ),
  515. SLOT( onDownloadJobStateChanged( DownloadJob::TrackState, DownloadJob::TrackState ) ) );
  516. }
  517. return m_downloadJob;
  518. }
  519. void
  520. Result::onDownloadJobStateChanged( DownloadJob::TrackState newState, DownloadJob::TrackState oldState )
  521. {
  522. if ( newState == DownloadJob::Aborted )
  523. {
  524. m_downloadJob.clear();
  525. emit updated();
  526. }
  527. }
  528. QWeakPointer<Result>
  529. Result::weakRef()
  530. {
  531. QMutexLocker lock( &m_mutex );
  532. return m_ownRef;
  533. }
  534. void
  535. Result::setWeakRef( QWeakPointer<Result> weakRef )
  536. {
  537. QMutexLocker lock( &m_mutex );
  538. m_ownRef = weakRef;
  539. }