File indexing completed on 2024-05-19 04:50:28

0001 /****************************************************************************************
0002  * Copyright (c) 2012 Matěj Laitl <matej@laitl.cz>                                      *
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 "CollectionProvider.h"
0018 
0019 #include "MetaValues.h"
0020 #include "amarokconfig.h"
0021 #include "core/collections/Collection.h"
0022 #include "core/collections/QueryMaker.h"
0023 #include "core/meta/Meta.h"
0024 #include "statsyncing/collection/CollectionTrack.h"
0025 
0026 using namespace StatSyncing;
0027 
0028 CollectionProvider::CollectionProvider( Collections::Collection *collection )
0029     : m_coll( collection )
0030 {
0031     Q_ASSERT( m_coll );
0032     connect( collection, &Collections::Collection::updated, this, &CollectionProvider::updated );
0033     connect( this, &CollectionProvider::startArtistSearch, this, &CollectionProvider::slotStartArtistSearch );
0034     connect( this, &CollectionProvider::startTrackSearch, this, &CollectionProvider::slotStartTrackSearch );
0035 }
0036 
0037 CollectionProvider::~CollectionProvider()
0038 {
0039 }
0040 
0041 QString
0042 CollectionProvider::id() const
0043 {
0044     return m_coll ? m_coll->collectionId() : QString();
0045 }
0046 
0047 QString
0048 CollectionProvider::prettyName() const
0049 {
0050     return m_coll ? m_coll->prettyName() : QString();
0051 }
0052 
0053 QIcon
0054 CollectionProvider::icon() const
0055 {
0056     return m_coll ? m_coll->icon() : QIcon();
0057 }
0058 
0059 qint64
0060 CollectionProvider::reliableTrackMetaData() const
0061 {
0062     if( id().startsWith(QLatin1String("amarok-nepomuk:")) )
0063         return Meta::valTitle | Meta::valArtist | Meta::valAlbum | Meta::valComposer |
0064                Meta::valTrackNr;
0065     else
0066         return Meta::valTitle | Meta::valArtist | Meta::valAlbum |
0067                Meta::valComposer | Meta::valYear | Meta::valTrackNr | Meta::valDiscNr;
0068 }
0069 
0070 qint64
0071 CollectionProvider::writableTrackStatsData() const
0072 {
0073     // TODO: this is unreliable and hacky, but serves for now:
0074     if( id() == QLatin1String("localCollection") )
0075         return Meta::valRating | Meta::valFirstPlayed | Meta::valLastPlayed | Meta::valPlaycount | Meta::valLabel;
0076     else
0077         return Meta::valRating | Meta::valFirstPlayed | Meta::valLastPlayed | Meta::valPlaycount;
0078 }
0079 
0080 Provider::Preference
0081 CollectionProvider::defaultPreference()
0082 {
0083     // currently only Local Collection and iPod one have good syncing capabilities
0084     if( id() == QLatin1String("localCollection") )
0085         return YesByDefault;
0086     if( id().startsWith( QLatin1String("amarok-ipodtrackuid") ) )
0087         return Ask;
0088     return NoByDefault;
0089 }
0090 
0091 QSet<QString>
0092 CollectionProvider::artists()
0093 {
0094     if( !m_coll )
0095         return QSet<QString>();
0096 
0097     m_foundArtists.clear();
0098     Q_EMIT startArtistSearch();
0099     m_queryMakerSemaphore.acquire(); // blocks until slotQueryDone() releases the semaphore
0100     QSet<QString> ret = m_foundArtists;
0101     m_foundArtists.clear();  // don't waste memory
0102 
0103     return ret;
0104 }
0105 
0106 TrackList
0107 CollectionProvider::artistTracks( const QString &artistName )
0108 {
0109     if( !m_coll )
0110         return TrackList();
0111 
0112     m_foundTracks.clear();
0113     Q_EMIT startTrackSearch( artistName );
0114     m_queryMakerSemaphore.acquire(); // blocks until slotQueryDone() releases the semaphore
0115     TrackList ret = m_foundTracks;
0116     m_foundTracks.clear();  // don't waste memory
0117     m_currentArtistName.clear();
0118 
0119     return ret;
0120 }
0121 
0122 void
0123 CollectionProvider::slotStartArtistSearch()
0124 {
0125     if( !m_coll )
0126     {
0127         m_queryMakerSemaphore.release(); // prevent deadlock
0128         return;
0129     }
0130 
0131     Collections::QueryMaker *qm = m_coll->queryMaker();
0132     qm->setAutoDelete( true );
0133     qm->setQueryType( Collections::QueryMaker::Artist );
0134     connect( qm, &Collections::QueryMaker::newArtistsReady,
0135              this, &CollectionProvider::slotNewArtistsReady );
0136     connect( qm, &Collections::QueryMaker::queryDone, this, &CollectionProvider::slotQueryDone );
0137     qm->run();
0138 }
0139 
0140 void
0141 CollectionProvider::slotStartTrackSearch( const QString &artistName )
0142 {
0143     if( !m_coll )
0144     {
0145         m_queryMakerSemaphore.release(); // prevent deadlock
0146         return;
0147     }
0148 
0149     Collections::QueryMaker *qm = m_coll->queryMaker();
0150     qm->setAutoDelete( true );
0151     qm->setQueryType( Collections::QueryMaker::Track );
0152     m_currentArtistName = artistName;
0153     qm->addFilter( Meta::valArtist, m_currentArtistName, true, true );
0154     connect( qm, &Collections::QueryMaker::newTracksReady,
0155              this, &CollectionProvider::slotNewTracksReady );
0156     connect( qm, &Collections::QueryMaker::queryDone, this, &CollectionProvider::slotQueryDone );
0157     qm->run();
0158 }
0159 
0160 void
0161 CollectionProvider::slotNewArtistsReady( Meta::ArtistList list )
0162 {
0163     foreach( const Meta::ArtistPtr &artist, list )
0164     {
0165         m_foundArtists.insert( artist->name() );
0166     }
0167 }
0168 
0169 void
0170 CollectionProvider::slotNewTracksReady( Meta::TrackList list )
0171 {
0172     foreach( Meta::TrackPtr track, list )
0173     {
0174         Meta::ArtistPtr artistPtr = track->artist();
0175         QString artist = artistPtr ? artistPtr->name() : QString();
0176         // QueryMaker interface is case-insensitive and cannot be configured otherwise.
0177         // StatSyncing::Provicer interface is case-sensitive, so we must filter here
0178         if( artist == m_currentArtistName )
0179             m_foundTracks.append( TrackPtr( new CollectionTrack( track ) ) );
0180     }
0181 }
0182 
0183 void
0184 CollectionProvider::slotQueryDone()
0185 {
0186     m_queryMakerSemaphore.release(); // unblock method in a worker thread
0187 }