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

0001 /****************************************************************************************
0002  * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@kde.org>                                *
0003  * Copyright (c) 2007 Adam Pigg <adam@piggz.co.uk>                                      *
0004  * Copyright (c) 2007,2008 Casey Link <unnamedrambler@gmail.com>                        *
0005  *                                                                                      *
0006  * This program is free software; you can redistribute it and/or modify it under        *
0007  * the terms of the GNU General Public License as published by the Free Software        *
0008  * Foundation; either version 2 of the License, or (at your option) any later           *
0009  * version.                                                                             *
0010  *                                                                                      *
0011  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0012  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0013  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0014  *                                                                                      *
0015  * You should have received a copy of the GNU General Public License along with         *
0016  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0017  ****************************************************************************************/
0018 
0019 #include "Mp3tunesServiceQueryMaker.h"
0020 
0021 #include "core/support/Amarok.h"
0022 #include "core/support/Debug.h"
0023 #include "Mp3tunesMeta.h"
0024 #include "Mp3tunesWorkers.h"
0025 #include "core-impl/collections/support/MemoryMatcher.h"
0026 
0027 #include <ThreadWeaver/Job>
0028 #include <ThreadWeaver/ThreadWeaver>
0029 #include <ThreadWeaver/Queue>
0030 
0031 #include <QList>
0032 
0033 using namespace Collections;
0034 
0035 class Mp3tunesServiceQueryMaker::Private {
0036 public:
0037     enum QueryType { NONE, TRACK, ARTIST, ALBUM, COMPOSER, YEAR, GENRE, CUSTOM };
0038     QueryType type;
0039     int maxsize;
0040 };
0041 
0042 
0043 Mp3tunesServiceQueryMaker::Mp3tunesServiceQueryMaker( Mp3tunesServiceCollection * collection, const QString &sessionId  )
0044     : DynamicServiceQueryMaker()
0045         , m_storedTransferJob( )
0046         , d( new Private )
0047 
0048 {
0049     DEBUG_BLOCK
0050     m_collection = collection;
0051     m_sessionId = sessionId;
0052 
0053     d->type = Private::NONE;
0054     d->maxsize = -1;
0055 }
0056 
0057 Mp3tunesServiceQueryMaker::Mp3tunesServiceQueryMaker( Mp3tunesLocker * locker, const QString &sessionId, Mp3tunesServiceCollection * collection  )
0058     : DynamicServiceQueryMaker()
0059         , m_storedTransferJob( )
0060         , d( new Private )
0061 {
0062     DEBUG_BLOCK
0063     m_collection = collection;
0064     m_sessionId = sessionId;
0065     m_locker = locker;
0066 
0067     d->type = Private::NONE;
0068     d->maxsize = -1;
0069 }
0070 
0071 Mp3tunesServiceQueryMaker::~Mp3tunesServiceQueryMaker()
0072 {
0073     delete d;
0074 }
0075 
0076 void Mp3tunesServiceQueryMaker::run()
0077 {
0078     DEBUG_BLOCK
0079     if ( m_storedTransferJob != 0 )
0080         return;
0081 
0082     m_collection->acquireReadLock();
0083     //naive implementation, fix this
0084     //note: we are not handling filtering yet
0085 
0086     if ( d->type == Private::NONE )
0087         //TODO error handling
0088         return;
0089     if (  d->type == Private::ARTIST )
0090         fetchArtists();
0091     else if (  d->type == Private::ALBUM )
0092         fetchAlbums();
0093     else if (  d->type == Private::TRACK )
0094         fetchTracks();
0095 
0096     m_collection->releaseLock();
0097 }
0098 
0099 
0100 void Mp3tunesServiceQueryMaker::abortQuery()
0101 {}
0102 
0103 QueryMaker*
0104 Mp3tunesServiceQueryMaker::setQueryType( QueryType type )
0105 {
0106     switch( type ) {
0107     case QueryMaker::Artist:
0108     case QueryMaker::AlbumArtist:
0109     {
0110         DEBUG_BLOCK
0111         d->type = Private::ARTIST;
0112         return this;
0113     }
0114 
0115     case QueryMaker::Album:
0116     {
0117         DEBUG_BLOCK
0118         d->type = Private::ALBUM;
0119         return this;
0120     }
0121 
0122     case QueryMaker::Track:
0123     {
0124         DEBUG_BLOCK
0125         d->type = Private::TRACK;
0126         return this;
0127     }
0128 
0129     case QueryMaker::Genre:
0130     case QueryMaker::Composer:
0131     case QueryMaker::Year:
0132     case QueryMaker::Custom:
0133     case QueryMaker::None:
0134     default:
0135         //TODO: Implement.
0136         return this;
0137     }
0138 }
0139 
0140 
0141 
0142 QueryMaker * Mp3tunesServiceQueryMaker::addMatch( const Meta::ArtistPtr & artist )
0143 {
0144     DEBUG_BLOCK
0145     if ( m_parentAlbumId.isEmpty() ) {
0146         const Meta::ServiceArtist * serviceArtist = static_cast< const Meta::ServiceArtist * >( artist.data() );
0147         m_parentArtistId = QString::number( serviceArtist->id() );
0148         debug() << "artist parent id set to: " << m_parentArtistId;
0149     }
0150 
0151     return this;
0152 }
0153 
0154 QueryMaker * Mp3tunesServiceQueryMaker::addMatch(const Meta::AlbumPtr & album)
0155 {
0156     DEBUG_BLOCK
0157     const Meta::ServiceAlbum * serviceAlbum = static_cast< const Meta::ServiceAlbum * >( album.data() );
0158     m_parentAlbumId = QString::number( serviceAlbum->id() );
0159     debug() << "album parent id set to: " << m_parentAlbumId;
0160     m_parentArtistId.clear();
0161 
0162     return this;
0163 }
0164 
0165 void Mp3tunesServiceQueryMaker::handleResult()
0166 {
0167     DEBUG_BLOCK
0168 }
0169 
0170 void Mp3tunesServiceQueryMaker::handleResult( const Meta::ArtistList & artists )
0171 {
0172     DEBUG_BLOCK
0173 
0174     if ( d->maxsize >= 0 && artists.count() > d->maxsize ) {
0175         emit newArtistsReady( artists.mid( 0, d->maxsize ) );
0176     } else {
0177         emit newArtistsReady( artists );
0178     }
0179 }
0180 
0181 void Mp3tunesServiceQueryMaker::handleResult( const Meta::AlbumList &albums )
0182 {
0183     DEBUG_BLOCK
0184 
0185     if ( d->maxsize >= 0 && albums.count() > d->maxsize ) {
0186         emit newAlbumsReady( albums.mid( 0, d->maxsize ) );
0187     } else {
0188         emit newAlbumsReady( albums );
0189     }
0190 }
0191 
0192 void Mp3tunesServiceQueryMaker::handleResult(const Meta::TrackList & tracks)
0193 {
0194     DEBUG_BLOCK
0195 
0196     if ( d->maxsize >= 0 && tracks.count() > d->maxsize ) {
0197         emit newTracksReady( tracks.mid( 0, d->maxsize ) );
0198     } else {
0199         emit newTracksReady( tracks );
0200     }
0201 }
0202 
0203 
0204 void Mp3tunesServiceQueryMaker::fetchArtists()
0205 {
0206     DEBUG_BLOCK
0207     if ( !m_artistFilter.isEmpty() )
0208     {
0209         debug() << "Artist Filtering";
0210         Mp3tunesSearchMonkey * searchMonkey = new Mp3tunesSearchMonkey( m_locker, m_artistFilter, Mp3tunesSearchResult::ArtistQuery );
0211         connect( searchMonkey, &Mp3tunesSearchMonkey::searchArtistComplete, this, &Mp3tunesServiceQueryMaker::artistDownloadComplete );
0212         ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(searchMonkey) ); //Go!
0213     } else if( m_locker->sessionValid() )
0214     {
0215         debug() << "Artist Fetching";
0216         Mp3tunesArtistFetcher * artistFetcher = new Mp3tunesArtistFetcher( m_locker );
0217         connect( artistFetcher, &Mp3tunesArtistFetcher::artistsFetched, this, &Mp3tunesServiceQueryMaker::artistDownloadComplete );
0218         ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(artistFetcher) );
0219     }
0220 }
0221 
0222 void Mp3tunesServiceQueryMaker::fetchAlbums()
0223 {
0224     DEBUG_BLOCK
0225 
0226     Meta::AlbumList albums;
0227 
0228     debug() << "Fetching Albums for parentArtist id: " << m_parentArtistId;
0229 
0230     if ( !m_parentArtistId.isEmpty() ) {
0231         albums = matchAlbums( m_collection, m_collection->artistById( m_parentArtistId.toInt() ) );
0232     } else {
0233         debug() << "parent id empty";
0234         return;
0235     }
0236 
0237     if ( albums.count() > 0 ) {
0238         handleResult( albums );
0239     } else if ( m_locker->sessionValid() ) {
0240         Mp3tunesAlbumWithArtistIdFetcher * albumFetcher = new Mp3tunesAlbumWithArtistIdFetcher( m_locker, m_parentArtistId.toInt() );
0241         connect( albumFetcher, &Mp3tunesAlbumWithArtistIdFetcher::albumsFetched, this, &Mp3tunesServiceQueryMaker::albumDownloadComplete );
0242 
0243         ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(albumFetcher) );
0244     } else {
0245         debug() << "Session Invalid";
0246     }
0247 }
0248 
0249 void Mp3tunesServiceQueryMaker::fetchTracks()
0250 {
0251     DEBUG_BLOCK
0252 
0253     Meta::AlbumList albums;
0254     Meta::TrackList tracks;
0255 
0256     debug() << "album parent id: " << m_parentAlbumId;
0257     debug() << "artist parent id: " << m_parentArtistId;
0258 
0259     if ( !m_parentArtistId.isEmpty() ) {
0260         ArtistMatcher artistMatcher( m_collection->artistById( m_parentArtistId.toInt() ) );
0261         tracks = artistMatcher.match( m_collection->trackMap().values() );
0262     } else if ( !m_parentAlbumId.isEmpty() ) {
0263         AlbumMatcher albumMatcher( m_collection->albumById( m_parentAlbumId.toInt() ) );
0264         tracks = albumMatcher.match( m_collection->trackMap().values() );
0265     } else {
0266         debug() << "parent id empty";
0267         return;
0268     }
0269 
0270     if ( tracks.count() > 0 ) {
0271         debug() << tracks.count() << " Tracks selected";
0272         handleResult( tracks );
0273         emit queryDone();
0274     } else if ( m_locker->sessionValid() ) {
0275         if( !m_parentArtistId.isEmpty() ) {
0276             debug() << "Creating track w/ artist id Fetch Worker";
0277             Mp3tunesTrackWithArtistIdFetcher * trackFetcher = new Mp3tunesTrackWithArtistIdFetcher( m_locker, m_parentArtistId.toInt() );
0278             connect( trackFetcher, &Mp3tunesTrackWithArtistIdFetcher::tracksFetched, this, &Mp3tunesServiceQueryMaker::trackDownloadComplete );
0279             ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(trackFetcher) ); //Go!
0280         } else if ( !m_parentAlbumId.isEmpty() ) {
0281             debug() << "Creating track w/ album id Fetch Worker";
0282             Mp3tunesTrackWithAlbumIdFetcher * trackFetcher = new Mp3tunesTrackWithAlbumIdFetcher( m_locker, m_parentAlbumId.toInt() );
0283             connect( trackFetcher, &Mp3tunesTrackWithAlbumIdFetcher::tracksFetched, this, &Mp3tunesServiceQueryMaker::trackDownloadComplete );
0284             ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(trackFetcher) ); //Go!
0285         }
0286     } else {
0287         debug() << "Session Invalid";
0288         return;
0289     }
0290 }
0291 
0292 void Mp3tunesServiceQueryMaker::artistDownloadComplete( QList<Mp3tunesLockerArtist> artistList )
0293 {
0294     DEBUG_BLOCK
0295 
0296     Meta::ArtistList artists;
0297 
0298     debug() << "Received artists";
0299     foreach(const Mp3tunesLockerArtist &artist, artistList) {
0300         Meta::ServiceArtist * serviceArtist = new Meta::ServiceArtist( artist.artistName() );
0301 
0302         //debug() << "Adding artist: " <<  artist.artistName();
0303 
0304         serviceArtist->setId( artist.artistId() );
0305 
0306         Meta::ArtistPtr artistPtr( serviceArtist );
0307 
0308         artists.push_back( artistPtr );
0309 
0310         m_collection->acquireWriteLock();
0311         m_collection->addArtist( artistPtr );
0312         m_collection->releaseLock();
0313 
0314     }
0315 
0316     handleResult( artists );
0317     emit queryDone();
0318 
0319 }
0320 
0321 void Mp3tunesServiceQueryMaker::albumDownloadComplete( QList<Mp3tunesLockerAlbum> albumsList )
0322 {
0323     DEBUG_BLOCK
0324 
0325     debug() << "Received albums";
0326 
0327     Meta::AlbumList albums;
0328     foreach(const Mp3tunesLockerAlbum &album, albumsList) {
0329 
0330         QString title = album.albumTitle();
0331         if ( title.contains("* PlayMix") ) continue;
0332         if ( title.isEmpty() ) title = "Unknown";
0333 
0334         QString albumIdStr = QString::number( album.albumId() );
0335         int albumId = album.albumId();
0336 
0337         bool hasArt = album.hasArt();
0338 
0339         Meta::Mp3TunesAlbum * serviceAlbum = new Meta::Mp3TunesAlbum( title );
0340 
0341         if ( hasArt )
0342         {
0343 
0344             QString coverUrl = "http://content.mp3tunes.com/storage/albumartget/<ALBUM_ID>?alternative=1&partner_token=<PARTNER_TOKEN>&sid=<SESSION_ID>";
0345 
0346             coverUrl.replace( "<SESSION_ID>", m_locker->sessionId() );
0347             coverUrl.replace( "<PARTNER_TOKEN>", m_locker->partnerToken() );
0348             coverUrl.replace( "<ALBUM_ID>", albumIdStr );
0349 
0350             serviceAlbum->setCoverUrl(coverUrl);
0351         }
0352 
0353         Meta::AlbumPtr albumPtr( serviceAlbum );
0354 
0355         //debug() << "Adding album: " <<  title;
0356 
0357         serviceAlbum->setId( albumId );
0358         m_collection->acquireWriteLock();
0359         m_collection->addAlbum( albumPtr );
0360         m_collection->releaseLock();
0361 
0362         Meta::ArtistPtr artistPtr = m_collection->artistById( album.artistId() );
0363         if ( artistPtr.data() != 0 )
0364         {
0365            //debug() << "Found parent artist";
0366             serviceAlbum->setAlbumArtist( artistPtr );
0367         }
0368 
0369         albums.push_back( albumPtr );
0370 
0371     }
0372 
0373     handleResult( albums );
0374     emit queryDone();
0375 
0376 }
0377 
0378 void Mp3tunesServiceQueryMaker::trackDownloadComplete( QList<Mp3tunesLockerTrack> tracksList )
0379 {
0380     DEBUG_BLOCK
0381     //debug() << "Received Tracks";
0382 
0383     Meta::TrackList tracks;
0384 
0385      //so lets figure out what we got here:
0386 
0387     foreach(const Mp3tunesLockerTrack &track, tracksList)
0388     {
0389 
0390         QString title = track.trackTitle();
0391         if ( title.isEmpty() ) title = "Unknown";
0392 
0393         Meta::Mp3TunesTrack * serviceTrack = new Meta::Mp3TunesTrack( title );
0394         Meta::TrackPtr trackPtr( serviceTrack );
0395 
0396       //  debug() << "Adding track: " <<  title;
0397 
0398         serviceTrack->setId( track.trackId() );
0399 
0400         serviceTrack->setUidUrl( track.playUrl() );
0401         serviceTrack->setDownloadableUrl( track.downloadUrl() );
0402 
0403         serviceTrack->setLength( track.trackLength() );
0404 
0405         serviceTrack->setTrackNumber( track.trackNumber() );
0406 
0407         serviceTrack->setYear( track.albumYear() );
0408 
0409         debug() << "setting type: " << Amarok::extension( track.trackFileName() );
0410         serviceTrack->setType( Amarok::extension( track.trackFileName() ) );
0411         //debug() << "set type";
0412         m_collection->acquireWriteLock();
0413         //debug() << "adding track";
0414         m_collection->addTrack( trackPtr );
0415         //debug() << "added tracktrack";
0416         m_collection->releaseLock();
0417         QString albumId = QString::number( track.albumId() );
0418         QString artistId = QString::number( track.artistId() );
0419 
0420         Meta::ArtistPtr artistPtr = m_collection->artistById( artistId.toInt() );
0421         if ( artistPtr.data() != 0 ) {
0422             debug() << "Found parent artist";
0423             Meta::ServiceArtist *artist = dynamic_cast< Meta::ServiceArtist * > ( artistPtr.data() );
0424             serviceTrack->setArtist( artistPtr );
0425             artist->addTrack( trackPtr );
0426         }
0427 
0428         Meta::AlbumPtr albumPtr = m_collection->albumById( albumId.toInt() );
0429         if ( albumPtr.data() != 0 ) {
0430             debug() << "Found parent album";
0431             Meta::ServiceAlbum *album = dynamic_cast< Meta::ServiceAlbum * > ( albumPtr.data() );
0432             serviceTrack->setAlbumPtr( albumPtr );
0433             album->addTrack( trackPtr );
0434         }
0435 
0436         tracks.push_back( trackPtr );
0437     }
0438 
0439     //ThreadWeaver::Weaver::instance()->dequeue( job );
0440     //job->deleteLater();
0441 
0442     handleResult( tracks );
0443     emit queryDone();
0444 
0445 }
0446 
0447 QueryMaker * Mp3tunesServiceQueryMaker::addFilter(qint64 value, const QString & filter, bool /*matchBegin*/, bool /*matchEnd*/)
0448 {
0449     DEBUG_BLOCK
0450     //debug() << "value: " << value;
0451     //for now, only accept artist filters
0452     if ( value == Meta::valArtist ) {
0453         //debug() << "Filter: " << filter;
0454         m_artistFilter = filter;
0455     }
0456     return this;
0457 }
0458 
0459 int Mp3tunesServiceQueryMaker::validFilterMask()
0460 {
0461     //we only support artist filters for now...
0462     return ArtistFilter;
0463 }
0464 
0465